??xml version="1.0" encoding="utf-8" standalone="yes"?>国产aⅴ激情无码久久,俺来也俺去啦久久综合网,久久亚洲精品成人AVhttp://www.shnenglu.com/Jeff-Chen/category/1417.htmlzh-cnSat, 31 May 2008 17:21:59 GMTSat, 31 May 2008 17:21:59 GMT60让你的SQLq行速度明显提高http://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7159.htmlJeff-ChenJeff-ChenMon, 15 May 2006 02:18:00 GMThttp://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7159.htmlhttp://www.shnenglu.com/Jeff-Chen/comments/7159.htmlhttp://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7159.html#Feedback0http://www.shnenglu.com/Jeff-Chen/comments/commentRss/7159.htmlhttp://www.shnenglu.com/Jeff-Chen/services/trackbacks/7159.html
一、不合理的烦引设?

  例:表record?20000行,试看在不同的索引下,下面几个 SQL的运行情况:



  1.在date上徏有一非个集索引
select count(*) from record where date >
''19991201'' and date < ''19991214''and amount >
2000 (25U?
select date,sum(amount) from record group by date
(55U?
select count(*) from record where date >
''19990901'' and place in (''BJ'',''SH'') (27U?

  分析Q?
  date上有大量的重复|在非集索引下,数据在物理上随机存放在数据页上,在范围查找时Q必L行一ơ表扫描才能扑ֈq一范围内的全部行?


  2.在date上的一个群集烦?br />select count(*) from record where date >
''19991201'' and date < ''19991214'' and amount >
2000 Q?4U)
select date,sum(amount) from record group by date
Q?8U)
select count(*) from record where date >
''19990901'' and place in (''BJ'',''SH'')Q?4U)

  分析Q?
  在群集烦引下Q数据在物理上按序在数据页上,重复g排列在一P因而在范围查找Ӟ可以先找到这个范围的h点,且只在这个范围内扫描数据,避免了大范围扫描Q提高了查询速度?


  3.在placeQdateQamount上的l合索引
select count(*) from record where date >
''19991201'' and date < ''19991214'' and amount >
2000 Q?6U)
select date,sum(amount) from record group by date
Q?7U)
select count(*) from record where date >
''19990901'' and place in (''BJ, ''SH'')Q?lt; 1U)

  分析Q?
  q是一个不很合理的l合索引Q因为它的前导列是placeQ第一和第二条SQL没有引用placeQ因此也没有利用上烦引;W三个SQL使用了place?br />

  4.在dateQplaceQamount上的l合索引
select count(*) from record where date >
''19991201'' and date < ''19991214'' and amount >
2000(< 1U?
select date,sum(amount) from record group by date
Q?1U)
select count(*) from record where date >
''19990901'' and place in (''BJ'',''SH'')Q?lt; 1U)

  分析Q?
  q是一个合理的l合索引。它?yu)date作ؓ前导列,使每个SQL都可以利用烦引,q且在第一和第三个SQL中Ş成了索引覆盖Q因而性能辑ֈ了最优?


  5.ȝQ?
  ~省情况下徏立的索引是非集索引Q但有时它ƈ不是最佳的Q合理的索引设计要徏立在对各U查询的分析和预上。一般来_

  ?有大量重复倹{且l常有范围查?

  Qbetween, >,< Q?gt;=,< =Q和order by、group by发生的列Q可考虑建立集索引Q?

  ?l常同时存取多列Q且每列都含有重复值可考虑建立l合索引Q?

  ?l合索引要尽量关键查询形成索引覆盖Q其前导列一定是使用最频繁的列?br />二、不充䆾的连接条?

  例:表card?896行,在card_no上有一个非聚集索引Q表account?91122行,?account_no上有一个非聚集索引Q试看在不同的表q接条g下,两个SQL的执行情况:
select sum(a.amount) from account a,
card b where a.card_no = b.card_noQ?0U)


  SQL改ؓQ?
select sum(a.amount) from account a,
card b where a.card_no = b.card_no and a.
account_no=b.account_noQ?lt; 1U)

  分析Q?
  在第一个连接条件下Q最x询方案是account作外层表Qcard作内层表Q利用card上的索引Q其I/Oơ数可由以下公式估算为:
  外层表account上的22541?Q外层表account?91122?内层表card上对应外层表W一行所要查扄3)=595907ơI/O

  在第二个q接条g下,最x询方案是card作外层表Qaccount作内层表Q利用account上的索引Q其I/Oơ数可由以下公式估算为:
  外层表card上的1944?Q外层表card?896?内层表account上对应外层表每一行所要查扄4)= 33528ơI/O

  可见Q只有充份的q接条gQ真正的最x案才会被执行?


  ȝQ?
  1.多表操作在被实际执行前,查询优化器会Ҏ(gu)q接条gQ列出几l可能的q接Ҏ(gu)q从中找出系l开销最的最x案。连接条件要充䆾考虑带有索引的表、行数多的表Q内外表的选择可由公式Q外层表中的匚w行数*内层表中每一ơ查扄ơ数定Q乘U最ؓ最x案?

  2.查看执行Ҏ(gu)的方?- 用set showplanonQ打开showplan选项Q就可以看到q接序、用何U烦引的信息Q想看更详细的信息,需用sa角色执行dbcc(3604,310,302)?


三、不可优化的where子句

  1.例:下列SQL条g语句中的列都建有恰当的烦引,但执行速度却非常慢Q?
select * from record where
substring(card_no,1,4)=''5378''(13U?
select * from record where
amount/30< 1000Q?1U)
select * from record where
convert(char(10),date,112)=''19991201''Q?0U)

  分析Q?
  where子句中对列的M操作l果都是在SQLq行旉列计算得到的,因此它不得不q行表搜索,而没有用该列上面的索引Q如果这些结果在查询~译时就能得刎ͼ那么可以被SQL优化器优化,使用索引Q避免表搜烦Q因此将SQL重写成下面这P
select * from record where card_no like
''5378%''Q?lt; 1U)
select * from record where amount
< 1000*30Q?lt; 1U)
select * from record where date= ''1999/12/01''
Q?lt; 1U)

  你会发现SQL明显快v来!

  2.例:表stuff?00000行,id_no上有非群集烦引,L下面q个SQLQ?
select count(*) from stuff where id_no in(''0'',''1'')Q?3U)

  分析Q?
  where条g中的''in''在逻辑上相当于''or''Q所以语法分析器会将in (''0'',''1'')转化为id_no =''0'' or id_no=''1''来执行。我们期望它会根据每个or子句分别查找Q再结果相加,q样可以利用id_no上的索引Q但实际上(Ҏ(gu)showplanQ?它却采用?OR{略"Q即先取出满x个or子句的行Q存入时数据库的工作表中,再徏立唯一索引以去掉重复行Q最后从q个临时表中计算l果。因此,实际q程没有利用id_no上烦引,q且完成旉q要受tempdb数据库性能的媄响?

  实践证明Q表的行数越??20000行时Q执行时间竟辑ֈ220U!q不如将or子句分开Q?
select count(*) from stuff where id_no=''0''
select count(*) from stuff where id_no=''1''

  得到两个l果Q再作一ơ加法合。因为每句都使用了烦引,执行旉只有3U,?20000行下Q时间也只有4U。或者,用更好的Ҏ(gu)Q写一个简单的存储q程Q?
create proc count_stuff as
declare @a int
declare @b int
declare @c int
declare @d char(10)
begin
select @a=count(*) from stuff where id_no=''0''
select @b=count(*) from stuff where id_no=''1''
end
select @c=@a+@b
select @d=convert(char(10),@c)
print @d

  直接出l果Q执行时间同上面一样快Q?

  ȝQ?br />
  可见Q所谓优化即where子句利用了烦引,不可优化卛_生了表扫描或额外开销?

  1.M对列的操作都导致表扫描Q它包括数据库函数、计表辑ּ{等Q查询时要尽可能操作移至等号右辏V?

  2.in、or子句怼使用工作表,使烦引失效;如果不生大量重复|可以考虑把子句拆开Q拆开的子句中应该包含索引?

  3.要善于用存储过E,它SQL变得更加灉|和高效?

  从以上这些例子可以看出,SQL优化的实质就是在l果正确的前提下Q用优化器可以识别的语句Q充份利用烦引,减少表扫描的I/Oơ数Q尽量避免表搜烦的发生。其实SQL的性能优化是一个复杂的q程Q上q这些只是在应用层次的一U体玎ͼ深入研究q会涉及数据库层的资源配|、网l层的流量控制以及操作系l层的M设计?br />来源Qhttp://edu.chinaz.com 

Jeff-Chen 2006-05-15 10:18 发表评论
]]>
五种提高SQL Server性能的方?/title><link>http://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7157.html</link><dc:creator>Jeff-Chen</dc:creator><author>Jeff-Chen</author><pubDate>Mon, 15 May 2006 02:02:00 GMT</pubDate><guid>http://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7157.html</guid><wfw:comment>http://www.shnenglu.com/Jeff-Chen/comments/7157.html</wfw:comment><comments>http://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7157.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.shnenglu.com/Jeff-Chen/comments/commentRss/7157.html</wfw:commentRss><trackback:ping>http://www.shnenglu.com/Jeff-Chen/services/trackbacks/7157.html</trackback:ping><description><![CDATA[有时Qؓ了让应用E序q行得更快,所做的全部工作是在这里或那里做一些很调整。啊Q但关键在于定如何q行调整Q迟早?zhn)会遇到这U情况:应用E序中的 SQL 查询不能按照(zhn)想要的方式q行响应。它要么不返回数据,要么耗费的时间长得出奇。如果它降低了报告或(zhn)的企业应用E序的速度Q用户必ȝ待的旉q长Q他们就会很不满意。就像?zhn)的父母不惛_(zhn)解释ؓ什么在深更半夜才回来一P用户也不会听你解释ؓ什么查?耗费q么长时间。(“对不vQ妈妈,我用了太多?LEFT JOIN。”)用户希望应用E序响应q速,他们的报告能够在瞬间之内q回分析数据。就我自p言Q如果在 Web 上冲时某个面要耗费十多U才能加载(好吧Q五U更实际一些)Q我也会很不耐烦?br /><br />Z解决q些问题Q重要的是找到问题的Ҏ(gu)。那么,从哪里开始呢Q根本原因通常在于<a target="_blank">数据?/a>设计和访问它的查询。在本月的专栏中Q我讲q四Ҏ(gu)术,q些技术可用于提高Z <a target="_blank">SQL Server</a>? 的应用程序的性能或改善其可׾~性。我仔l说?LEFT JOIN、CROSS JOIN 的用以?IDENTITY 值的索。请CQ根本没有神奇的解决Ҏ(gu)。调整?zhn)?a target="_blank">数据?/a>及其查询需要占用时间、进行分析,q需要大量的试。这些技术都已被证明行之有效Q但Ҏ(gu)的应用程序而言Q可能其中一些技术比另一些技术更适用?br /><br />?INSERT q回 IDENTITY <br /><br />我决定从遇到许多问题的内容入手:如何在执?SQL INSERT 后检?IDENTITY 倹{通常Q问题不在于如何~写索值的查询Q而在于在哪里以及何时q行索。在 <a target="_blank">SQL Server</a> 中,下面的语句可用于索由最新在zd<a target="_blank">数据?/a>q接上运行的 SQL 语句所创徏?IDENTITY |<br /><br />SELECT @@IDENTITY<br /><br />q个 SQL 语句q不复杂Q但需要记住的一Ҏ(gu)Q如果这个最新的 SQL 语句不是 INSERTQ或者?zhn)针对?INSERT SQL 的其他连接运行了?SQLQ则不会获得期望的倹{?zhn)必须q行下列代码才能索紧跟在 INSERT SQL 之后且位于同一q接上的 IDENTITYQ如下所C:<br /><br />INSERT INTO Products (ProductName) VALUES ('Chalk')<br /><br />SELECT @@IDENTITY<br /><br />在一个连接上针对 Northwind <a target="_blank">数据?/a>q行q些查询返回一个名UCؓ Chalk 的新产品?IDENTITY 倹{所以,在?ADO ?Visual Basic? 应用E序中,可以q行以下语句Q?br /><br />Set oRs = oCn.Execute("SET NOCOUNT ON;INSERT INTO Products _<br /><br />(ProductName) VALUES ('Chalk');SELECT @@IDENTITY")<br /><br />lProductID = oRs(0) <br /><br />  此代码告?<a target="_blank">SQL Server</a> 不要q回查询的行计数Q然后执?INSERT 语句Qƈq回刚刚个新行创建的 IDENTITY 倹{SET NOCOUNT ON 语句表示q回的记录集有一行和一列,其中包含了这个新?IDENTITY 倹{如果没有此语句Q则会首先返回一个空的记录集Q因?INSERT 语句不返回Q何数据)Q然后会q回W二个记录集Q第二个记录集中包含 IDENTITY 倹{这可能有些令h困惑Q尤其是因ؓ(zhn)从来就没有希望q?INSERT 会返回记录集。之所以会发生此情况,是因?<a target="_blank">SQL Server</a> 看到了这个行计数Q即一行受到媄响)q将其解释ؓ表示一个记录集。因此,真正的数据被推回CW二个记录集。当然?zhn)可以使?ADO 中的 NextRecordset Ҏ(gu)获取此第二个记录集,但如果总能够首先返回该记录集且只返回该记录集,则会更方便,也更有效率?br /><br />此方法虽然有效,但需要在 SQL 语句中额外添加一些代码。获得相同结果的另一Ҏ(gu)是在 INSERT 之前使用 SET NOCOUNT ON 语句Qƈ?SELECT @@IDENTITY 语句攑֜表中?FOR INSERT 触发器中Q如下面的代码片D|C。这PMq入该表?INSERT 语句都将自动q回 IDENTITY 倹{?br /><br />CREATE TRIGGER trProducts_Insert ON Products FOR INSERT AS <br /><br />SELECT @@IDENTITY <br /><br />GO<br /><br />触发器只?Products 表上发生 INSERT 时启动,所以它L会在成功 INSERT 之后q回一?IDENTITY。用此技术,(zhn)可以始l以相同的方式在应用E序中检?IDENTITY 倹{?br /><br />内嵌视图与时表 <br /><br />某些时候,查询需要将数据与其他一些可能只能通过执行 GROUP BY 然后执行标准查询才能攉的数据进行联接。例如,如果要查询最C个定单的有关信息Q?zhn)首先需要知道是哪些定单。这可以使用q回定单 ID ?SQL 查询来检索。此数据׃存储在时表Q这是一个常用技术)中,然后?Products 表进行联接,以返回这些定单售出的产品数量Q?br /><br />CREATE TABLE #Temp1 (OrderID INT NOT NULL, _<br /><br />OrderDate DATETIME NOT NULL)<br /><br />INSERT INTO #Temp1 (OrderID, OrderDate)<br /><br />SELECT TOP 5 o.OrderID, o.OrderDate<br /><br />FROM Orders o ORDER BY o.OrderDate DESC<br /><br />SELECT p.ProductName, SUM(od.Quantity) AS ProductQuantity<br /><br />FROM #Temp1 t <br /><br />INNER JOIN [Order Details] od ON t.OrderID = od.OrderID<br /><br />INNER JOIN Products p ON od.ProductID = p.ProductID <br /><br />GROUP BY p.ProductName<br /><br />ORDER BY p.ProductName<br /><br />DROP TABLE #Temp1<br /><br />q些 SQL 语句会创Z个时表Q将数据插入该表中,其他数据与该表q行联接Q然后除去该临时表。这会导致此查询q行大量 I/O 操作Q因此,可以重新~写查询Q用内嵌视囑֏代时表。内嵌视囑֏是一个可以联接到 FROM 子句中的查询。所以,(zhn)不用在 tempdb 中的临时表上耗费大量 I/O 和磁盘访问,而可以用内嵌视囑־到同Ll果Q?br /><br />SELECT p.ProductName, <br /><br />SUM(od.Quantity) AS ProductQuantity<br /><br />FROM (<br /><br />SELECT TOP 5 o.OrderID, o.OrderDate<br /><br />FROM Orders o <br /><br />ORDER BY o.OrderDate DESC<br /><br />) t <br /><br />INNER JOIN [Order Details] od ON t.OrderID = od.OrderID<br /><br />INNER JOIN Products p ON od.ProductID = p.ProductID<br /><br />GROUP BY<br /><br />p.ProductName<br /><br />ORDER BY<br /><br />p.ProductName <br /><br />此查询不仅比前面的查询效率更高,而且长度更短。时表会消耗大量资源。如果只需要将数据联接到其他查询,则可以试试用内嵌视图,以节省资源?br /><br />避免 LEFT JOIN ?NULL <br /><br />当然Q有很多时候?zhn)需要执?LEFT JOIN 和?NULL 倹{但是,它们q不适用于所有情c改?SQL 查询的构建方式可能会产生一个花几分钟运行的报告~短到只花几U钟q样的天壤之别的效果。有Ӟ必须在查询中调整数据的Ş态,使之适应应用E序所要求的显C方式。虽?TABLE 数据cd会减大量占用资源的情况Q但在查询中q有许多区域可以q行优化。SQL 的一个有价值的常用功能?LEFT JOIN。它可以用于索第一个表中的所有行、第二个表中所有匹配的行、以及第二个表中与第一个表不匹配的所有行。例如,如果希望q回每个客户及其定单Q?LEFT JOIN 则可以显C有定单和没有定单的客户?br /><br />此工具可能会被过度用。LEFT JOIN 消耗的资源非常之多Q因为它们包含与 NULLQ不存在Q数据匹配的数据。在某些情况下,q是不可避免的,但是代h(hun)可能非常高。LEFT JOIN ?INNER JOIN 消耗资源更多,所以如果?zhn)可以重新~写查询以得该查询不用Q?LEFT JOINQ则会得到非常可观的回报?br /><br />加快使用 LEFT JOIN 的查询速度的一Ҏ(gu)术涉及创Z?TABLE 数据cdQ插入第一个表QLEFT JOIN 左侧的表Q中的所有行Q然后用第二个表中的值更?TABLE 数据cd。此技术是一个两步的q程Q但与标准的 LEFT JOIN 相比Q可以节省大量时间。一个很好的规则是尝试各U不同的技术ƈ记录每种技术所需的时_直到获得用于(zhn)的应用E序的执行性能最佳的查询?br /><br />试查询的速度Ӟ有必要多ơ运行此查询Q然后取一个^均倹{因为查询(或存储过E)可能会存储在 <a target="_blank">SQL Server</a> 内存中的q程~存中,因此W一ơ尝试耗费的时间好像稍长一些,而所有后l尝试耗费的时间都较短。另外,q行(zhn)的查询Ӟ可能正在针对相同的表q行其他查询。当其他查询锁定和解锁这些表Ӟ可能会导致?zhn)的查询要排队{待。例如,如果(zhn)进行查询时某h正在更新 此表中的数据Q则在更新提交时(zhn)的查询可能需要耗费更长旉来执行?br /><br />避免使用 LEFT JOIN 旉度降低的最单方法是可能多地围l它们设?a target="_blank">数据?/a>。例如,假设某一产品可能hcd也可能没有类别。如?Products 表存储了其类别的 IDQ而没有用于某个特定品的cdQ则(zhn)可以在字段中存?NULL 倹{然后?zhn)必须执?LEFT JOIN 来获取所有品及其类别。?zhn)可以创徏一个gؓ“No Category”的cdQ从而指定外键关pM允许 NULL 倹{通过执行上述操作Q现在?zhn)可以?INNER JOIN 索所有品及其类别了。虽然这看v来好像是一个带有多余数据的变通方法,但可能是一个很有h(hun)值的技术,因ؓ它可以消?SQL 批处理语句中消耗资源较多的 LEFT JOIN。在<a target="_blank">数据?/a>中全部用此概念可以为?zhn)节省大量的处理时间。请CQ对于?zhn)的用戯言Q即使几U钟的时间也非常重要Q因为当(zhn)有许多用户正在讉K同一个联?a target="_blank">数据?/a>应用E序Ӟq几U钟实际上的意义会非帔R大?br /><br />灉|使用W卡乘U?<br /><br />对于此技巧,我将q行非常详细的介l,q提倡在某些情况下用笛卡尔乘积。出于某些原因,W卡乘U?(CROSS JOIN) 遭到了很多谴责,开发h员通常会被警告Ҏ(gu)׃要用它们。在许多情况下,它们消耗的资源太多Q从而无法高效用。但是像 SQL 中的M工具一P如果正确使用Q它们也会很有h(hun)倹{例如,如果(zhn)想q行一个返回每月数据(即某一特定月䆾客户没有定单也要q回Q的查询Q?zhn)可以很方便C用笛卡尔乘积?br /><br />虽然q看h好像没什么神奇的Q但是请考虑一下,如果(zhn)从客户到定单(q些定单按月份进行分lƈ寚w售额q行计Q进行了标准?INNER JOINQ则只会获得客户有定单的月䆾。因此,对于客户未订购Q何品的月䆾Q?zhn)不会获?0 倹{如果?zhn)想ؓ每个客户都绘制一个图Q以昄每个月和该月销售额Q则可能希望此图包括月销售额?0 的月份,以便直观标识些月份。如果?Figure 2Q最后一) 中的 SQLQ数据则会蟩q销售额?0 元的月份,因ؓ在定单表中对于零销售额不会包含M行(假设(zhn)只存储发生的事Ӟ?br /><br />Figure 3Q最后一)中的代码虽然较长Q但是可以达到获取所有销售数据(甚至包括没有销售额的月份)的目标。首先,它会提取d所有月份的列表Q然后将它们攑օW一?TABLE 数据cd?(@tblMonths) 中。下一步,此代码会获取在该旉D内有销售额的所有客户公司的名称列表Q然后将它们攑օ另一?TABLE 数据cd?(@tblCus-tomers) 中。这两个表存储了创徏l果集所必需的所有基本数据,但实际销售数量除外?W一个表中列Z所有月份(12 行)Q第二个表中列出了这个时间段内有销售额的所有客P对于我是 81 个)。ƈ非每个客户在q去 12 个月中的每个月都购买了品,所以,执行 INNER JOIN ?LEFT JOIN 不会q回每个月的每个客户。这些操作只会返回购C品的客户和月份?br /><br />W卡乘U则可以q回所有月份的所有客戗笛卡尔乘积基本上是第一个表与第二个表相乘,生成一个行集合Q其中包含第一个表中的行数与第二个表中的行数相乘的l果。因此,W卡乘U会向表 @tblFinal q回 972 行。最后的步骤是用此日期范围内每个客L月销售额总计更新 @tblFinal 表,以及选择最l的行集?br /><br />如果׃W卡乘U占用的资源可能会很多,而不需要真正的W卡乘U,则可以}慎地使用 CROSS JOIN。例如,如果对品和cd执行?CROSS JOINQ然后?WHERE 子句、DISTINCT ?GROUP BY 来筛选出大多数行Q那么?INNER JOIN 会获得同Ll果Q而且效率高得多。如果需要ؓ所有的可能性都q回数据Q例如在(zhn)希望用每月销售日期填充一个图表时Q,则笛卡尔乘积可能会非常有帮助。但是,(zhn)不应该它们用于其他用途,因ؓ在大多数Ҏ(gu)?INNER JOIN 的效率要高得多?br /><br />N补零 <br /><br />q里介绍其他一些可帮助提高 SQL 查询效率的常用技术。假设?zhn)按区域?gu)有销售h员进行分lƈ他们的销售额q行计Q但是?zhn)只想要那?a target="_blank">数据?/a>中标Cؓ处于zd状态的销售h员。?zhn)可以按区域对销售h员分l,q?HAVING 子句消除那些未处于活动状态的销售h员,也可以在 WHERE 子句中执行此操作。在 WHERE 子句中执行此操作会减需要分l的行数Q所以比?HAVING 子句中执行此操作效率更高。HAVING 子句中基于行的条件的{选会强制查询寚w些在 WHERE 子句中会被去除的数据q行分组?br /><br />另一个提高效率的技巧是使用 DISTINCT 关键字查找数据行的单独报表,来代替?GROUP BY 子句。在q种情况下,使用 DISTINCT 关键字的 SQL 效率更高。请在需要计聚合函敎ͼSUM、COUNT、MAX {)的情况下再?GROUP BY。另外,如果(zhn)的查询L自己q回一个唯一的行Q则不要使用 DISTINCT 关键字。在q种情况下,DISTINCT 关键字只会增加系l开销?br /><br />(zhn)已l看CQ有大量技术都可用于优化查询和实现特定的业务规则,技巧就是进行一些尝试,然后比较它们的性能。最重要的是要测试、测试、再试。在此专栏的来各期内容中,我将l箋深入讲述 <a target="_blank">SQL Server</a> 概念Q包?a target="_blank">数据?/a>设计、好的烦引实践以?<a target="_blank">SQL Server</a> 安全范例?br /><br />Figure 2 Returning All Customers and Their Sales <br /><br />set nocount on<br /><br />DECLARE @dtStartDate DATETIME, <br /><br />@dtEndDate DATETIME,<br /><br />@dtDate DATETIME<br /><br />SET @dtEndDate = '5/5/1997'<br /><br />SET @dtEndDate = DATEADD(DD, -1, CAST(CAST((MONTH(@dtEndDate) + 1) <br /><br />AS VARCHAR(2)) + '/01/' + CAST(YEAR(@dtEndDate) AS VARCHAR(4)) + ' <br /><br />23:59:59' AS DATETIME))<br /><br />SET @dtStartDate = DATEADD(MM, -1 * 12, @dtEndDate)<br /><br />SELECT CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +<br /><br />CASE <br /><br />WHEN MONTH(o.OrderDate) < 10 <br /><br />THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br /><br />ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br /><br />END AS sMonth,<br /><br />c.CustomerID,<br /><br />c.CompanyName,<br /><br />c.ContactName,<br /><br />SUM(od.Quantity * od.UnitPrice) AS mSales<br /><br />FROM Customers c<br /><br />INNER JOIN Orders o ON c.CustomerID = o.CustomerID<br /><br />INNER JOIN [Order Details] od ON o.OrderID = od.OrderID<br /><br />WHERE o.OrderDate BETWEEN @dtStartDate AND @dtEndDate<br /><br />GROUP BY<br /><br />CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +<br /><br />CASE <br /><br />WHEN MONTH(o.OrderDate) < 10 <br /><br />THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br /><br />ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br /><br />END,<br /><br />c.CustomerID,<br /><br />c.CompanyName,<br /><br />c.ContactName<br /><br />ORDER BY<br /><br />c.CompanyName,<br /><br />sMonth<br /><br /><br /><br /><br /><br /><br /><br />___________________________________________________________________________<br /><br />Figure 3 Cartesian Product at Work<br /><br />DECLARE @tblMonths TABLE (sMonth VARCHAR(7))<br /><br />DECLARE @tblCustomers TABLE ( CustomerID CHAR(10),<br /><br />CompanyName VARCHAR(50),<br /><br />ContactName VARCHAR(50))<br /><br />DECLARE @tblFinal TABLE ( sMonth VARCHAR(7), <br /><br />CustomerID CHAR(10),<br /><br />CompanyName VARCHAR(50),<br /><br />ContactName VARCHAR(50),<br /><br />mSales MONEY)<br /><br />DECLARE @dtStartDate DATETIME, <br /><br />@dtEndDate DATETIME,<br /><br />@dtDate DATETIME,<br /><br />@i INTEGER<br /><br />SET @dtEndDate = '5/5/1997'<br /><br />SET @dtEndDate = DATEADD(DD, -1, CAST(CAST((MONTH(@dtEndDate) + 1) AS <br /><br />VARCHAR(2)) + '/01/' + CAST(YEAR(@dtEndDate) AS VARCHAR(4)) + ' <br /><br />23:59:59' AS DATETIME))<br /><br />SET @dtStartDate = DATEADD(MM, -1 * 12, @dtEndDate)<br /><br />?Get all months into the first table<br /><br />SET @i = 0<br /><br />WHILE (@i < 12)<br /><br />BEGIN<br /><br />SET @dtDate = DATEADD(mm, -1 * @i, @dtEndDate)<br /><br />INSERT INTO @tblMonths SELECT CAST(YEAR(@dtDate) AS VARCHAR(4)) + '-' +<br /><br />CASE <br /><br />WHEN MONTH(@dtDate) < 10 <br /><br />THEN '0' + CAST(MONTH(@dtDate) AS VARCHAR(2))<br /><br />ELSE CAST(MONTH(@dtDate) AS VARCHAR(2))<br /><br />END AS sMonth<br /><br />SET @i = @i + 1<br /><br />END<br /><br />?Get all clients who had sales during that period into the "y" table<br /><br />INSERT INTO @tblCustomers<br /><br />SELECT DISTINCT<br /><br />c.CustomerID,<br /><br />c.CompanyName,<br /><br />c.ContactName<br /><br />FROM Customers c<br /><br />INNER JOIN Orders o ON c.CustomerID = o.CustomerID<br /><br />WHERE o.OrderDate BETWEEN @dtStartDate AND @dtEndDate<br /><br />INSERT INTO @tblFinal<br /><br />SELECT m.sMonth,<br /><br />c.CustomerID,<br /><br />c.CompanyName,<br /><br />c.ContactName,<br /><br />0<br /><br />FROM @tblMonths m CROSS JOIN @tblCustomers c<br /><br /><br /><br />UPDATE @tblFinal SET <br /><br />mSales = mydata.mSales<br /><br />FROM @tblFinal f INNER JOIN <br /><br />(<br /><br />SELECT c.CustomerID,<br /><br />CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +<br /><br />CASE WHEN MONTH(o.OrderDate) < 10 <br /><br />THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br /><br />ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br /><br />END AS sMonth,<br /><br />SUM(od.Quantity * od.UnitPrice) AS mSales<br /><br />FROM Customers c<br /><br />INNER JOIN Orders o ON c.CustomerID = o.CustomerID<br /><br />INNER JOIN [Order Details] od ON o.OrderID = od.OrderID<br /><br />WHERE o.OrderDate BETWEEN @dtStartDate AND @dtEndDate<br /><br />GROUP BY<br /><br />c.CustomerID,<br /><br />CAST(YEAR(o.OrderDate) AS VARCHAR(4)) + '-' +<br /><br />CASE WHEN MONTH(o.OrderDate) < 10 <br /><br />THEN '0' + CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br /><br />ELSE CAST(MONTH(o.OrderDate) AS VARCHAR(2))<br /><br />END<br /><br />) mydata on f.CustomerID = mydata.CustomerID AND f.sMonth = <br /><br />mydata.sMonth <br /><br />SELECT f.sMonth,<br /><br />f.CustomerID,<br /><br />f.CompanyName,<br /><br />f.ContactName,<br /><br />f.mSales<br /><br />FROM @tblFinal f<br /><br />ORDER BY<br /><br />f.CompanyName,<br /><br />f.sMonth<!-- / message --><br /><br />来源Qhttp://www.chinahtml.com<img src ="http://www.shnenglu.com/Jeff-Chen/aggbug/7157.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.shnenglu.com/Jeff-Chen/" target="_blank">Jeff-Chen</a> 2006-05-15 10:02 <a href="http://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7157.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>搜烦引擎设计http://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7153.htmlJeff-ChenJeff-ChenMon, 15 May 2006 01:51:00 GMThttp://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7153.htmlhttp://www.shnenglu.com/Jeff-Chen/comments/7153.htmlhttp://www.shnenglu.com/Jeff-Chen/archive/2006/05/15/7153.html#Feedback0http://www.shnenglu.com/Jeff-Chen/comments/commentRss/7153.htmlhttp://www.shnenglu.com/Jeff-Chen/services/trackbacks/7153.html
  W者现在专门负责网上山东(http://www.china-sd.netQ中׃搜烦版块的徏设,利用最常用的开发语a--asp开发搜索引擎的强大功能Q下面我搜索引擎主要组成部分和其中一些功能的实现代码讲解l大Ӟ有什么不之处请大家l予指出Q?

  在这一章节中,我介l一下搜索引擎的l成部分和主要功能?

  搜烦引擎的组成,大致分ؓ三部分:

  1、界面:q一部分主要是面向客LQ是可以看到的部分,比如(zhn)打开search.sina.com.cn事后看到的页面?

  2、程序:q一部分主要是执行代码,Ҏ(gu)客户的搜索要求去执行代码从而获得搜索结果;q些是我们看不到的?

  3、数据库Q所有的搜烦引擎都离不开数据库,q著名的google.com也不例外Q数据库是储存搜索资料的仓库Q储存的多Q搜索得到的资料׃多Q这也是搜烦引擎是否强大的闪耀点之一?

   那么搜烦引擎是否强大q有其他的闪耀点喽Q是什么呢Q对Q搜索引擎数据库中的存储资料再多Q我们不能够方便的去查找搜烦Q甚x找不到所需的资料,那么q个数据库就是“死”的Q毫无用处可aQ所以程序代码v到非帔R要的作用?

   讲到q里Q我应该l大家介l一下搜索引擎的几个主要功能Q?

   1、搜索查询:毫无疑问q是最基本的功能了Q根据关键字扑ֈW合关键字的相关资料?

   2、分|C:如果你搜索到的资料非常多Q都攑֜一个页面里Q那L人的感觉׃使ؕp糟的一片;分页昄Ҏ(gu)Z看书的习惯,一部分内容攑ֈW一,其他的内Ҏ(gu)到第二页、第三页{等?

   3、搜索统计:一般包括查询资料的数量Q分几个面Q每个页面含几个资料Q当前页面资料范围等{?

   4、搜索结果编排:搜烦排名我想大家不会陌生Q这些是l合|站搜烦引擎挣money的一Ҏ(gu)施,q也是强大搜索引擎中不可~少的功能;比如Ҏ(gu)点击量排名,Ҏ(gu)收费排名、根据等U排名?

   5、多个关键字查询Q“如果要查找包含多个关键词的信息Q可以用I格把关键词隔开”这是新搜索引擎版面中的一D|字,在一个文本框中打上多个关键字搜烦查询资料?

   6、整体统计:q个是对搜烦引擎开通至今一些数据统计,包含“热门查询关键字”统计、数据库中资料整体统计、每个类别所含资料统计等{?

   以上功能代码主要Ҏ(gu)W者的要求来书写,大家可以在我写的代码上做修改Q以成ؓ你自己需要的功能代码?

  好了Q经q了一节的热n后,我们也可以进入实战阶D,首先Q我们先Z个数据库Q作料的存储Q这里我数据库的文件名为information.mdbQ用access创徏数据库,当然你也可以使用sqlserver创徏?

  建立四个表:www(存储资料),sort(大类)Qsamll(类),key(查询关键?

    1、www表:id---自动~号Qsitename---站点名称Qurl---站点链接Qfaq---要说明,key---关键字,time---d旉,level---站点{Qsortid---大类idQsmallid---类idQhot---站点点击ơ数?

    2、sort表:id---自动~号,sort

    3、small表:id---自动~号,small

    4、key表:keyname---关键字;keyhot---出现的次?

    用asp建立与数据库的连接:conn.asp

  

  说明Q用Server.MapPathQ)表示的\径ؓ文g的相对\径,我这里conn.asp和information.mdb在同一个目录下。我惌些都很简单,大家很容易理解和接受的!好,数据库建立h后,我们可以徏讑ּ大功能的搜烦引擎。请期待哦!d~~~~

  用asp制作强大的搜索引?-- 模糊搜烦

  Ҏ(gu)一个关键字Q搜索到相关的资料,q里的“相关”是指资料中有类D个关键字的字W串。例如:“山东”这个关键字Q只要数据库中资料里包含“山东”这个关键字的都要把它们扑և来。模p搜索的应用其实很简单,只要使用一个sql语句可以实玎ͼ下面׃看看他的语句的写法?

  sql语法中你会发现这么几个判定词QLIKE、NOT LIKE?BETWEEN?LIKE判定词是一个非常有用的W号。不q,在很多情况下用了它可能会带给你太多的数据Q所以在用到它之前最好先开动脑{多x自己到底惌得什么数据。NOT LIKE是反光而行了。BETWEEN假设你想取出一定范围内的数据,而且你事先知道范围的L和终点,那么你不妨采用BETWEEN 判断词。这几个判定词根据不同的环境使用Q一般最常用的就是like?%"l合了?

  dim sql,key

  key=request("key")

  sql="select * from www where sitename like '%"&key&"%' or faq like '%"&key&"%' or key like '%"&key&"%' "

  说明Q这里的sql语句目的是索数据库中sitename字段中是否包含keyQfaq字段中是否包含keyQkey字段中是否包含keyQ这样做的目的是让搜索的范围包含到“站点名U”、“站点简要说明”、“站点关键字”。如果你只想搜烦关键字只要?sql="select * from www where key like '%"&key&"%' " 可以了。“like”中都用了“or”来相连Q“or?“或者”的意思,意思是不论哪一个like W合条gQ都要把搜烦到的资料输出昄出来?

  OKQ现在大可不必去看看能不能执行或者说执行的结果如何,因ؓ搜烦引擎大部分功能的实现都是靠sql语句的书写了。等我把其他的相关sql语句的功能实Cl完后,大家再看看效果,呵呵Q别着急!Q?
来源Qhttp://edu.chinaz.com

Jeff-Chen 2006-05-15 09:51 发表评论
]]>
vaþþþ| 91þþƷƵ| AVһȾþ| ŷ˾þۺһ | þ޾ƷƷ| ˾þۺϳ| Ʒþþþþ| ޾ƷNVþþþþþþþ| ɫۺϾþĻ| þav߳avav紵| ˾þô߽avӰԺ| þѹƷһ| þþþ޾Ʒվ| þþþĻƷ| þֻоƷ߹ۿ| 91龫Ʒ91þþþ| ھƷþ| ʵҶ԰׾ʾþ| ƷŷþþӰ| þþþþϸ| þѹƵ| þAVۺϺɫ| ŷ޾þav| Ʒþþþ| һaƬþëƬ| AþþƷ| պŷۺϾþӰԺDs | ŷþþҹһĻ | ԴӰȷþԴ| 99þۺϹƷ| þþƷAɫ| Ʒþþþ| ˾ƷþѶ| þóۺɫۺ| AVһȾþ| þþƷAV㽶| ޹˾þһWWW| ŷ龫Ʒþþþþ| þþ91뾫ƷHD| ˾þۺ2020| ޾Ʒþ|