初探Sql Server 执行计划及Sql查询优化

作者:perfectaction 2006.11.07
目的:写此文与和我一样在数据库边缘学习的朋友一起探讨、进步。
原址:http://blog.csdn.net/no_mIss/archive/2006/11/09/1374978.aspx

         http://www.leadbbs.com/a/a.asp?B=230&ID=2507764

 

网上关与sql server优化的文章很多,有很多都是N前的前辈所写,对于sql server2000/2005已不太适用,自己在使用过程中,慢慢发现了许多,比如IN、OR、AND、很多很多,有时候还经常看到很多人用程测出仅几 S甚至几MS的时间差的例子来证明着什么,让许多人不知道其是对还是错。而SQL优化又是每个要与数据库打交道的程序员的必修课,所以写了此文,与朋友们 共勉。 谈到优化就必然要涉及索引,就像要讲锁必然要说事务一样,所以你需要了解一下索引,仅仅是索引,就能讲半天了,所以索引我就不说了(打很多字是很累的,况 且我也知之甚少),可以去参考相关的文章,这个网上资料比较多了。

今天来讨论下MSSQL的执行计划,来让大家知道如何查看MSSQL的优化机制,以此来优化SQL查询,而不是仅仅用程序执行结果来优化。

--DROP TABLE T_UserInfo--------------------------------------建测试表
CREATE TABLE T_UserInfo
(
    Userid varchar(20),  UserName varchar(20),
    RegTime datetime, Tel varchar(20),
)
--插入测试数据
DECLARE @I INT
DECLARE @ENDID INT
SELECT @I = 1
SELECT @ENDID = 100  --在此处更改要插入的数据,重新插入之前要删掉所有数据
WHILE @I <= @ENDID
BEGIN
    INSERT INTO T_UserInfo  
    SELECT ’ABCDE’+CAST(@I AS VARCHAR(20))+’EF’,’李’+CAST(@I AS VARCHAR(20)),GETDATE(),’876543’+CAST(@I AS VARCHAR(20))
    SELECT @I = @I + 1
END

--相关SQL语句解释
-------------------------------------------------------------建聚集索引
CREATE CLUSTERED INDEX INDEX_Userid  ON T_UserInfo (Userid)
--建非聚集索引
CREATE NONCLUSTERED INDEX INDEX_Userid  ON T_UserInfo (Userid)
--删除索引
DROP INDEX T_UserInfo.INDEX_Userid
-----------------------------------------------------------
-------------------------------------------------------------
显示有关由Transact-SQL 语句生成的磁盘活动量的信息
SET STATISTICS IO ON
--关闭有关由Transact-SQL 语句生成的磁盘活动量的信息
SET STATISTICS IO OFF
--显示[返回有关语句执行情况的详细信息,并估计语句对资源的需求]
SET SHOWPLAN_ALL  ON  
--关闭[返回有关语句执行情况的详细信息,并估计语句对资源的需求]
SET SHOWPLAN_ALL  OFF
-----------------------------------------------------------
请记住:SET STATISTICS IO 和 SET SHOWPLAN_ALL 是互斥的。

OK ,现在开始: 首先,我们插入 100 条数据
然后我写了一个查询语句:
SELECT * FROM T_UserInfo WHERE USERID='ABCDE6EF' 选中以上语句,按Ctrl+L,如下图   这就是 MSSQL 的执行计划:表扫描:扫描表中的行  
然后我们来看该语句对 IO 的读写:
执行:SET STATISTICS IO ON
此时再执行该SQL:SELECT * FROM T_UserInfo WHERE USERID='ABCDE6EF'
切换到消失栏显示如下:
    表'T_UserInfo'。扫描计数1,逻辑读1 次,物理读0 次,预读0 次。
解释下其意思:
    四个值分别为:    
         执行的扫描次数;    
       从数据缓存读取的页数 ;    
        从磁盘读取的页数;    
        为进行查询而放入缓存的页数
重要:如果对于一个 SQL 查询有多种写法,那么这四个值中的逻辑读 ( logical reads) 决定了哪个是最优化的。  

接下来我们为其建一个聚集索引
执行CREATE CLUSTERED INDEX INDEX_Userid  ON T_UserInfo (Userid)
然后再执行SELECT * FROM T_UserInfo WHERE USERID='ABCDE6EF'
切换到消息栏如下显示:
    表'T_UserInfo'。扫描计数1,逻辑读2 次,物理读0 次,预读0 次。
此时逻辑读由原来的1变成2, 说明我们又加了一个索引页,现在我们查询时,逻辑读就是要读两页(1索引页+1数据页),此时的效率还不如不建索引。  
此时再选中查询语句,然后再Ctrl+L,如下图:
聚集索引查找:扫描聚集索引中特定范围的行 说明,此时用了索引。  
OK, 到这里你应该已经知道初步知道 MSSQL 查询计划和如何查看对 IO 的读取消耗了吧!    

接下来我们继续:  
现在我再把测试数据改变成1000条
再执行SET STATISTICS IO ON,
再执行 SELECT * FROM T_UserInfo WHERE USERID='ABCDE6EF'
在不加聚集索引的情况下:
    表'T_UserInfo'。扫描计数1,逻辑读7 次,物理读0 次,预读0 次。
    在加聚集索引的情况下:CREATE CLUSTERED INDEX INDEX_Userid  ON T_UserInfo (Userid)
    表'T_UserInfo'。扫描计数1,逻辑读2 次,物理读0 次,预读0 次。
(其实也就是说此时是读了一个索引页,一个数据页) 如此,在数据量稍大时,索引的查询优势就显示出来了。       

先小总结下当你构建 SQL 语句时,按 Ctrl+L 就可以看到语句是如何执行,是用索引扫描还是表扫描? 通过 SET STATISTICS IO ON 来查看逻辑读,完成同一功能的不同 SQL 语句,逻辑读 越小查询速度越快 ( 当然不要找那个只有几百条记录的例子来反我 )    

我们再继续深入:
OK,现在我们再来看一次,我们换个SQL语句,来看下MSSQL如何来执行的此SQL呢?
现在去掉索引:DROP INDEX T_UserInfo.INDEX_Userid
现在打开[显示语句执行情况的详细信息]:SET SHOWPLAN_ALL  ON
然后再执行:SELECT * FROM T_UserInfo WHERE USERID LIKE 'ABCDE8%'
看结果栏:结果中有些具体参数,比如IO的消耗,CPU的消耗。
在这里我们只看StmtText:
SELECT * FROM T_UserInfo WHERE USERID LIKE 'ABCDE8%'  
    |--Table Scan(OBJECT:([student].[dbo].[T_UserInfo]), WHERE:(like([T_UserInfo].[Userid], 'ABCDE8%', NULL))) Ctrl+L看下此时的图行执行计划:  

我再加上索引:
先关闭:SET SHOWPLAN_ALL OFF
再执行:CREATE CLUSTERED INDEX INDEX_Userid  ON T_UserInfo (Userid)
再开启:SET SHOWPLAN_ALL ON
再执行:SELECT * FROM T_UserInfo WHERE USERID LIKE 'ABCDE8%'
查看StmtText:
SELECT * FROM T_UserInfo WHERE USERID LIKE 'ABCDE8%'  
    |--Clustered Index Seek(OBJECT:([student].[dbo].[T_UserInfo].[INDEX_Userid]), SEEK:([T_UserInfo].[Userid] >= 'ABCDE8' AND [T_UserInfo].[Userid] < 'ABCDE9'),   WHERE:(like([T_UserInfo].[Userid], 'ABCDE8%', NULL)) ORDERED FORWARD)Ctrl+L看下此时的图行执行计划: Ctrl+L看下此时的图行执行计划:    
在有索引的情况下,我们再写一个SQL:
SET SHOWPLAN_ALL ON SELECT * FROM T_UserInfo WHERE LEFT(USERID,4)='ABCDE8%'
查看StmtText:
SELECT * FROM T_UserInfo WHERE LEFT(USERID,4)='ABCDE8%'  
    |--Clustered Index Scan(OBJECT:([student].[dbo].[T_UserInfo].[INDEX_Userid]), WHERE:(substring([T_UserInfo].[Userid], 1, 4)='ABCDE8%')) Ctrl+L看下此时的图行执行计划:  
我们再分别看一下三种情况下对IO的操作 分别如下:
第一种情况:表'T_UserInfo'。扫描计数1,逻辑读7 次,物理读0 次,预读0 次。
第二种情况:表'T_UserInfo'。扫描计数1,逻辑读3 次,物理读0 次,预读0 次。
第三种情况:表'T_UserInfo'。扫描计数1,逻辑读8 次,物理读0 次,预读0 次。

这说明:
第一次是表扫描,扫了 7 页,也就是全表扫描
第二次是索引扫描,扫了 1 页索引, 2 页数据页
第三次 是索引扫描 + 表扫描,扫了 1 页索引, 7 页数据页
[图形界面也有对CPU和IO的消耗,也可以看出来哪个最优!]    

通过比较,嘿嘿,很容易的看出:第二种第三种写法在都有索引的情况下,like有效的使用索引,而left则不能,这样一个最简单的优化的例子就出来了。    
如果以上你都明白了,那么你可能已经对SQL的优化有初步新的想法了,网上一堆堆的SQL优化的文章真的是那样吗?你自己试试就知道了,而不必盲目去记那些东西,自己试试,看看MSSQL到底是怎么来执行就明白了。

重要: 在 我举的例子中,用的是聚集索引扫描,字段是字母加数字,大家可以试试看纯数字的、字母的、汉字的等等,了解下MMSQL会如何改变SQL语句来利用索引。 然后再试试非聚集索引是什么情况?用不用索引和什么有关?子查询MSSQL是如何执行?IN用不用索引,LIKE用不用索引?函数用不用索引?OR、 AND、UNION?子查询呢?在这里我不一一去试给大家看了,只要知道了如何去看MSSQL的执行计划(图形和文本),很多事情就很明朗了。  

大总结: 实现同一查询功能的SQL写法可能会有多种,如果判断哪种最优化,如果仅仅是从时间上来测,会受很多外界因素的影响,而我们明白了MSSQL如何去执行, 通过IO逻辑读、通过查看图示的查询计划、通过其优化后而执行的SQL语句,才是优化SQL的真正途径。   另外提醒下:数据量的多少有时会影响MSSQL对同一种查询写法语句的执行计划,这一点在非聚集索引上特别明显,还有就是在多CPU与单CPU下,在多用 户并发情况下,同一写法的查询语句执行计划会有所不同,这个就需要大家有机会去试验了(我也没有这方面的太多经验与大家分享)。   先写这些吧,由于我对MSSQL认识还很浅薄,如有不对的地方,还请指正。

 

(二)关于执行计划

 

转载自:http://blog.csdn.net/xiao_hn/archive/2009/06/11/4259628.aspx

 

当需要分析某个查询的效能时,最好的方式之一查看这个查询的执行计划。执行计划描述 SQL Server 查询优化器如何实际运行 ( 或者将会如何运行 ) 一个特定的查询。

 

查看查询的执行计划有几种不同的方式。它们包括:

 

SQL Server 查询分析器里有一个叫做 显示实际执行计划 的选项 ( 位于 查询 下拉菜单中 ) 。如果打开了这个选项,那么无论何时在查询分析器中运行一个查询,都会得到一个显示在单独窗口的查询执行计划 ( 以图形的格式 )

 

如果只是想看下执行计划而不想运行查询,那么可以选择 显示预估的执行计划 选项 ( 位于 查询 下拉菜单中 ) 。当选择这个选项后,执行计划会马上显示出来 ( 以图形的格式 ) 。两者的不同之处在于当实际运行一个查询时,当前的服务器上的运算也会被考虑进去。大多数情况下,两种方式产生的执行计划产生的结果是相似的。

 

当建立一个 SQL Server Profiler 追踪时,可以收集的一个事件是 MISC: Execution Plan. 这个信息 ( 以文本的形式 ) 显示查询优化器用来执行查询的计行计划。

 

可以在查询分析器上执行 SET SHOWPLAN_TEXT ON 命令。这条命令被执行后,所有在当前这个查询分析器会话中执行的查询都不会运行,而是会显示一个基于文本的执行计划。执行某条用到临时表的查询时,必须在执行查询先运行 SET STATISTICS PROFILE ON 语句。

 

上面这些选项中,我更喜欢使用 显示实际执行计划 这个选项。它以图形的方式输出信息,并且考虑到了当前服务器上的那些运算。 [7.0, 2000] Updated 8-5-2005

 

*****

 

如果在执行计划中看到如下所示的任何一项,就应该将它们视作警告信号并调查它们以找出潜在的性能问题。从性能方面来说,下面所示的每一项都是不理想的。

 

Index or table scans( 索引或者表扫描 ) 可能意味着需要更好的或者额外的索引。

Bookmark Lookups( 书签查找 ) 考虑修改当前的聚集索引,使用复盖索引,限制 SELECT 语句中的字段数量。

Filter( 过滤 ) WHERE 从句中移除用到的任何函数,不要在 SQL 语句中包含视图,可能需要额外的索引。

Sort( 排序 ) 数据是否真的需要排序?可否使用索引来避免排序?在客户端排序是否会更加有效率?

 

无一例外地避免这些操作是不可能的,但是避免得越多,查询性能就会越快。 [7.0,2000,2005]

 

*****

 

如果有在存储过程中或者其它 T-SQL 批处理代码中用到了临时表,就不能在查询分析器或 Management Studio 使用 显示预估的执行计划 选项来评估查询。必须实际运行这个存储过程或者批处理代码。这是因为使用 显示预估的执行计划 选项来运行一个查询时,它并没有实际被运行,临时表也没有创建。由于临时表没有被创建,参考到临时表的代码就会失败,导致预估的执行计划不能成创建成功。

 

从另一方面来说,如果使用的是表变量而不是临时表,则可以使用 显示预估的执行计划 选项。 [7.0,2000,2005] Updated 8-5-2005

 

*****

 

 

如果在查询分析器或 Management Studio 中对一个非常复杂的查询的执行计划进行分析,可能会觉得它的执行计划既难于看懂也难于分析。那么,按照查询的逻辑将它拆分成几个部分,然后分别对这些部分进行分析会容易得多。 [7.0,2000,2005] Updated 8-5-2005

 

*****

 

 

图形执行计划并不总是容易读懂和解释。查看执行计划时记住如下几点:

 

非常复杂的执行计划会被分成多个部分,它们分别列出在屏幕上。每个部分分别代表查询优化器为了得到最终结果而必须执行的单个处理或步骤。

 

执行计划的每个步骤经常会被拆分成一个个更小的子步骤。不幸的是,它们是从右至左显示在屏幕上的。这意味着你必须滚动到图形执行计划的最右边去查看每个步骤是从哪儿开始的。

 

每个步骤与子步骤间通过箭头连接,藉此显示查询执行的路径。

 

最后,查询的所有部分在屏幕顶部的左边汇总到一起。

 

如果将鼠标移动到任何执行计划任何步骤或者子步骤的上面,就会显示一个弹出式窗口,上面显示该步骤或子步骤的更加详细的信息。

 

如果将鼠标移动到连接步骤或子步骤的箭头上,就可以看到一个弹出式窗口,上面显示有多少笔记录从一个步骤或子步骤移动到另一个步骤或子步骤。

[7.0, 2000, 2005] Updated 8-5-2005

 

 

图形执行计划上连接每个图标的箭头粗细不同。 箭头的粗细表示每个图标之间移动的数据行数量以及数据行大小移动所需的相对成本。 箭头越粗,相对成本就越高。

 

 

可以使用这个指示器来快速测量一个查询。你可能会特别关注粗箭头以了解它如何影响到查询的效能。例如,粗线头应该在图形执行计划的右边,而非左边。如果看到它们在左边,就意味着太多的数据行被返回,这个执行计划也不是最佳的执行计划。 [7.0,2000,2005]

*****

 

 

执行计划的每个部分都被分配了一个成本百分比。 它表示这个部分耗用了整个执行计划的多少资源。当对一个执行计划进行分析的时候,应该将精力集中于有着高成本百分比的那些部分。这样就可以在有限的时间里找到可能性最大的问题,从而回报了你在时间上的投资。 [7.0, 2000, 2005]

*****

 

  你可能会注意到一个执行计划的某些部分被执行了不止一次。 作为执行计划分析的一部分,应该将你的一些时间集中在任何执行了超过一次的那些部分上,看看是否有什么方式减少它们执行的次数。执行的次数越少,查询的速度就越快。 [7.0, 2000, 2005]

*****

 

  在执行计划中你可以看到 I/O CPU 成本 。它们没有 实际 的意义,例如代表特定资源的使用量。查询优化器使用这些数字来做出最佳选择。它们可用来参考的一个意义是,较小的 I/O CPU 成本比较大的 I/O CPU 成本使用更少的服务器资源。 [7.0, 2000, 2005]

*****

 

 

查看 SQL Server 图形执行计划时, 可以查找的非常有用的一个东西就是查询优化器如何为给定的查询使用索引来从表中获取数据。 通过查看是否有用到索引,以及索引如何被使用,都有助于判断当前的索引是否使得查询执行得尽可能的快。

将鼠标移到图形执行计划上的表名 ( 以及它的图标 ) 上面,就会弹出一个窗口,从它上面可以看到一些信息。这些信息让你知道是否有用到索引来从表中获取数据,以及它是如何使用的。这些信息包括:

·      Table Scan( 表扫描 ) :如果看到这个信息,就说明数据表上没有聚集索引,或者查询优化器没有使用索引来查找。意即资料表的每一行都被检查到。如果资料表相对较小的话,表扫描可以非常快速,有时甚至快过使用索引。

因 此,当看到有执行表扫描时,第一件要做的事就是看看数据表有多少数据行。如果不是太多的话,那么表扫描可能提供了最好的总体效能。但如果数据表大的话,表 扫描就极可能需要长时间来完成,查询效能就大受影响。在这种情况下,就需要仔细研究,为数据表增加一个适当的索引用于这个查询。

假设你发现某查询使用了表扫描,有一个合适的非聚集索引,但它没有用到。这意味着什么呢?为什么这个索引没有用到呢?如果需要获得的数据量相对数据表大小来说非常大,或者数据选择性不高 ( 意味着同一个字段中重复的值很多 ) ,表扫描经常会比索引扫描快。例如,如果一个数据表有 10000 个数据行,查询返回 1000 行,如果这个表没有聚集索引的话,那么表扫描将比使用一个非聚集索引更快。或者如果数据表有 10000 个数据行,且同一个字段 (WHERE 条件句有用到这个字段 ) 上有 1000 笔重复的数据,表扫描也会比使用非聚集索引更快。

查看图形执行计划上的数据表上的弹出式窗口时,请注意 预估的资料行数 (Estimated Row Count)” 。这个数字是查询优化器作出的多少个数据行会被返回的最佳推测。如果执行了表扫描且 预估的数据行数 数值很高的话,就意味着返回的记录数很多,查询优化器认为执行表扫描比使用可用的非聚集索引更快。

·      Index Seek( 索引查找 ) :索引查找意味着查询优化器使用了数据表上的非聚集索引来查找数据。性能通常会很快,尤其是当只有少数的数据行被返回时。

·      Clustered Index Seek( 聚集索引查找 ) :这指查询优化器使用了数据表上的聚集索引来查找数据,性能很快。实际上,这是 SQL Server 能做的最快的索引查找类型。

·      Clustered Index Scan( 聚集索引扫描 ) : 聚集索引扫描与表扫描相似,不同的是聚集索引扫描是在一个建有聚集索引的数据表上执行的。和一般的表扫描一样,聚集索引扫描可能表明存在效能问题。一般来 说,有两种原因会引此聚集索引扫描的执行。第一个原因,相对于数据表上的整体数据行数目,可能需要获取太多的数据行。查看 预估的数据行数量 (Estimated Row Count)” 可以对此加以验证。第二个原因,可能是由于 WHERE 条 件句中用到的字段选择性不高。在任何情况下,与标准的表扫描不同,聚集索引扫描并不会总是去查找数据表中的所有数据,所以聚集索引扫描一般都会比标准的表 扫描要快。通常来说,要将聚集索引扫描改成聚集索引查找,你唯一能做的是重写查询语句,让语句限制性更多,从而返回更少的数据行。

[7.0, 2000, 2005]

 

绝大多数情况下,查询优化器会对连接进行分析,按最有效率的顺序,使用最有效率的连接类型来对数据表进行连接。 但并不总是如此。在图形执行计划中你可以看到代表查询所使用到的各种不同连接类型的图标。此外,每个连接图标都有两个箭头指向它。指向连接图标的上面的箭头代表该连接的外部表,下面的箭头则代表这个连接的内部表。箭头的另一头则指向被连接的数据表名。

 

 

有 时在多表连接的查询中,箭头的另一头指向的并不是一个数据表,而是另一个连接。如果将鼠标移到指向外部连接与内部连接的箭头上,就可以看到一个弹出式窗 口,告诉你有多少数据行被发送至这个连接来进行处理。外部表应该总是比内部表含有更少的数据行。如果不是,则说明查询优化器所选择的连接顺序可能不正确 ( 下面是关于这个话题的更多信息 )

 

 

首先,让我们来看看连接类型。 SQL Server 可以使用三种不同的技术来连接资料表:嵌套循环 (nested loop) ,散列 (hash) ,以及合并 (merge) 。一般来说,嵌套循环是最快的连接类型,但如果不可能使用嵌套循环的话,则会用到散列或者合并作为合适的连接类型。两者都比嵌套循环连接慢。

 

 

当连接大表时,则合并连接可能是最佳选项,而非嵌套循环连接。唯一的明确这一点的方式是对两者都进行测试以查看哪一个最有效率。

 

 

如果你怀疑某个查询速度慢的原因可能是因为它所使用的连接类型不理想,那么你可以使用连接提示来复盖查询优化器的选择。在使用连接提示之前,你需要花费一些时间去了解一下每种连接类型以及它们的工作方式。这是一个复杂的话题,超出了本文的讨论范围。

 

 

查询优化器选择最有效率的连接类型来连接数据表。例如,嵌套循环连接的外部表应该是连接的两个表中较小的那个表。散列连接也是一样,它的外部表应该是较小的那个表。如果你觉得查询优化器选择的连接顺序是错误的,可以使用连接提示来复盖它。

 

 

很多情况下,唯一的确认使用连接提示改变连接类型或连接顺序是提升还是降低了效能的方式,就是对它们进行测试,看看发生了什么。 [7.0, 2000, 2005]

*****

 

如果你的 SQL Server 有多个 CPU ,并且没有修改 SQL Server 的默认设置来限制 SQL Server 使用服务器上所有 CPU 的能力,那么 查询优化器会考虑使用平行处理 (parallelism) 来执行某些查询 。平行处理指在多个 CPU 上同时运行一个查询的能力。很多情况下,一个运行在多个处理器上的查询比仅运行在单个处理器上的查询要快,但并不总是这样。

 

 

查询优化器并不会总是使用平行处理,即使在它能使用的时候。这是因为查询优化器在决定使用平行处理前会考虑到各种不同的因素。例如当前 SQL Server 上处于活动状态的连接数量, CPU 忙 碌程度,是否有足够的内存来运行平行化查询,需要处理的数据行数量,以及这个查询的类型。查询优化器收集到这些真实的数据后,再决定平行处理是不是运行这 个查询的最佳选择。你可能会发现,某次一个查询没有用到平行处理,但稍后某次再次运行同样的查询时,却又用到了平行处理。

 

 

有时,使用多个处理器所需的花费会大于使用它们能所能节省的资源。尽管查询处理器的确会衡量使用平行查询的正反两面的影响,但它的猜想并不总是正确的。

 

 

如果怀疑平行处理防碍了某条查询的性能,你可以使用 OPTION (MAXDOP 1) 提示来关闭该查询的平行处理。

决定是否使用平行处理的唯一方式是通过这两种方式对查询进行测试,看看发生了什么。 [7.0, 2000, 2005]

*****

 

 

查看图形执行计划时,你可能会发现某个图标的文字用红色显示, 而非通常情况下的黑色。这意味着相关的表的一些统计数据遗失,统计数据是查询优化器生成一个好的执行计划所必须的。

 

 

遗失的统计数据可以通过右键这个图标,并选择 创建遗失的统计资料 来创建。这时会弹出 创建遗失的统计数据 对话框,通过它可以很容易地创建遗失的统计数据。

 

 

当可以选择去更新遗失的统计资料时,应该总是这样做,因为这样极有可能让你正在分析的查询语句从中获得效能上的好处。 [7.0, 2000, 2005]

*****

 

 

有时你会在图形执行计划上看到标识了 ”Assert” 的图标。 这意味着查询优化器正在验证查询语句是否有违反引用完整性或者条件约束。如果没有,则没有问题。但如果有的话,查询优化器将无法为该查询建立执行计划,同时会产生一个错误。 [7.0, 2000, 2005]

*****

 

 

你常常会在图形执行计划上看到标识成 书签查找 (Bookmark Lookup )” 的图标。 书签查找相当常见。书签查找的本质是告诉你查询处理器必须从数据表或者聚集索引中来查找它所需要的数据行,而不是从非聚集索引中直接读取。

 

 

打比方说,如果一个查询语句的 SELECT,JOIN 以及 WHERE 子句中的所有字段,都不存在于那个用来定位符合查询条件的数据行的非聚集索引中,那么查询优化器就不得不做额外的工作在数据表或聚集索引中查找那些满足这个查询语句的字段。

 

 

另一种引起书签查找的原因是使用了 SELECT * 。由于在绝大多情况下它会返回比你实际所需更多的数据,所以应该永不使用 SELECT *.

 

 

从性能方面来说,书签查找是不理想的。因为它会请求额外的 I/O 开销在字段中查找以返回所需的数据行。

 

 

如果认为 书签查找防碍了查询的性能,那么有四种选择可以用来避免它:可以建立 WHERE 子句会用到的聚集索引,利用索引交集的优势,建立覆盖的非聚集索引,或者 ( 如果是 SQL Server 2000/2005 企业版的话 ) 可以建立索引视图。如果这些都不可能,或者使用它们中的任何一个都会耗用比书签查找更多的资源,那么书签查找就是最佳的选择了。 [7.0, 2000, 2005]

 

有时查询优化器需要在 tempdb 数据库中建立临时工作表。 如果是这样的话,就意味着图形执行计划中有标识成 Index Spool, Row Count Spool 或者 Table Spool 的图标。

 

 

任何时候,使用到工作表一般都会防碍到性能,因为需要额外的 I/O 开销来维护这个工作表。理想情况下应该不要用到工作表。不幸的是并不能总是避免用到工作表。有时当使用工作表比其它选择更有效率时,它的使用实际上会增强性能。

 

 

不论何种情况,图形执行计划中的工作表都应该引起你的警觉。应该仔细检查这样的查询语句,看看是否有办法重写查询来避免用到工作表。有可能没有办法。但如果有的话,你就朝提升这个查询的性能方面前进了一步。 [7.0, 2000, 2005]

*****

 

 

在图形执行计划上看到流聚合 ( Stream Aggregate ) 图标就意味着有对一个单一的输入进行了聚合。 当使用了 DISTINCT 子句,或者任何聚合函数时,如 AVG, COUNT, MAX, MIN, 或者 SUM 等,流聚合操作就相当常见。   [7.0, 2000, 2005]

*****

 

 

查询分析器与 Management Studio 不是唯一的可以生成 显示查询执行计划的工具。 SQL Server Profiler 也可以显示执行计划,但格式是文本形式的。使用 SQL Server Profiler 来显示执行计划的一个优势是,它能为实际运行的大量查询产生执行计划。如果使用查询分析器和 Management Studio ,则一次只能运行一个。

 

 

使用 Profiler 捕获 、显示执行计划时,必须使用如下的配置生成一个追踪:

 

捕获事件

·      Performance: Execution Plan

·      Performance: Show Plan All

·      Performance: Show Plan Statistics

·      Performance: Show Plan Text

 

显示的字段

·      StartTime

·      Duration

·      TextData

·      CPU

·      Reads

·      Writes

 

过滤条件

·      Duration 。你会想指定最大的查询执行时间,例如 5 秒钟,由此避免得到太大量的数据。

 

当然,你可以在你的追踪中捕获更多的没有例在上面的信息,上面例出的只是一个指南而已。但必须记住不要去捕获太多的数据,否则,追踪的运行会影响服务器的性能。 [7.0, 2000, 2005]

*****

 

 

如果在查询中使用了 OPTION FAST 提示, 那就必须小心执行计划的结果可能不是你所期望的。这时你所看到的执行计划基于使用了 FAST 提示的结果,而不是整个查询语句的实际执行计划。

 

 

FAST 提示用来告知果询优化器尽可能快地返回指定行数的数据行,即便这样做会防碍查询的整体性能。使用这个提示的目的在于为使用者快速返回特定行数的记录,由此让他们产生速度非常快速的错觉。。当返回指定行数的数据行后,剩余的数据行按照它们通常的速度返回。

 

 

因此,如果使用了 FAST 提示,那么生成的执行计划只是基于那些 FAST 返回的数据行,而非查询要返回的所有数据行。如果想看所有数据行的执行计划,那么就必须移除这个 FAST 提示。 [2000,2005]

 

你可能感兴趣的:(初探Sql Server 执行计划及Sql查询优化)