执行计划查看


Warning: Undefined array key "HTTP_REFERER" in /www/wwwroot/prod/www.enjoyasp.net/wp-content/plugins/google-highlight/google-hilite.php on line 58

1,查看执行计划方式:
1)以行表方式返回执行计划信息(树状结构,自上而下,自左而右查看,通过TotalSubtreeCost查看开销),不执行sql语句
set showplan_all on
go
select * from AWBuildVersion
set showplan_all off

2)XML方式返回执行计划信息,不执行sql语句
set showplan_XML on
select * from AWBuildVersion
set showplan_XML off

3)以行表方式返回执行计划信息,执行sql语句,因为执行了sql语句,故在返回的执行计划结果中包含了每一步执行后返回的行数(表头的rows字段),可与
预估的行数做比较,分析执行计划的效果。
set statistics profile on
select * from AWBuildVersion
set statistics profile off
4)对于执行计划,分析其是否恰当,首先要看预估行数 estimaterows与rows是否相同,若差别较大,差几千,那么说明预估出问题,
原因是统计信息不对,这时可通过重建索引来更新统计信息。(重建索引的好处:1,更新了统计信息,执行计划预估更加正确,2,处理了数据碎片,查找速度提升。)
第二就是查看totalsubtreecost开销。

执行计划结果表信息:
ROWS:执行计划的每一步返回的实际行数。
Executes:执行计划的每一步被运行了多少次:若此值很大,又发生在nested loop中,要看是否应重新编译,以使用Hash JOIN
StmtText:执行计划的具体内容。
EstimateRows:预估的每一步返回的行数。要与ROWS做比对,以分析预估是否正确。
EstimateIO:每一步预估的IO开销。
EstimateCPU:每一步预估的CPU开销。
TotalSubtreeCost:据EstimateIO与EstimateCPU通过某种计算公式,计算出每一步执行计划子树的cost,包含自己的cost和它的所有下层步骤的cost总和。
Warnings:SqlServer执行每一步时遇到的警告,如某一步没有统计信息运行预估等。
Parallel:是否使用了并行的执行计划。


2,JOIN连接种类
1)Nested Loops JOIN:对于A表中满足条件的每一行,遍历B表,在执行计划信息中,以Nested包括,共有两行,每行执行过滤后,以Nested进行连接。
                     选过滤后连接。
强制用: inner loop/merge/hash join
优点:不需要SQLSERVER为JOIN建立额外的数据结构,也不用占用tempdb空间。
不足:复杂度是两表行数相乘,适用于两表数据集比较小的情况下。B表最好有索引。
2)Merge Join:从A表中取一条记录,B表中也取一条,比较是否相等,若相等,则两行连接起来返回,若不等,则舍掉小的那个值,
接顺序取下一个较大的值进行比较,直到A与B表其中之一遍历完。
由此定义可以:1,Merge Join要求两表是排序过的,若没有排序,则会执行先排序,故附加作用是返回的结果都是有序的。
              2,只能进行值相等的运算,ON条件后为=。
              3,时间复杂度是每表符合条件的行数,它适用于大数据量的情况。
              4,为防止数据有重复而被过掉的结果,会对B表已遍历过的放到tempdb中,以备查询,称之为many-to-many
          故由上知,它的复杂度低,若表中无索引,要排序。它还需要额外的many-to-many,不过若表字段限定unique,则相当于告诉sqlserver
这是唯一的,不会重复,那么也就不会用many-to-many了。
3)Hash Join:以哈希算法为主的连接方法,分为两步,第一步,在内存或tempdb中对B表建立hash表,第二步,将另一表值代入查找。适用于
大数据量的情况,特别是无索引这种的无序数据。它建立hash表,故要汪消耗内存,要进行hash匹配,要消耗CPU.

对照表如下:
  Nested Loop Joion Merge Join Hash Join
适用场景 小数据量  数据量中等 数据量大
ON是否要求相等 不需要   需要  需要
是否使用内存 不需要   不使用  需要使用内存建立hash表。
是否使用tempdb 不需要   many-to-many用 使用建立hash表

3, 其它运算符
1)流运算:Stream Aggregation(将数据集排成一个队列以后做运算),如执行聚合函数、Group By时,会出现流聚合。
2) 哈希匹配:Hash Aggregation(类似于Hash Join,需要SQL Server先建立Hash表,然后才能做运算)如执行聚合函数时,数据量大时,会出现哈希匹配。
3)连接:Concatenationunion all与union:会有一个连接操作,名为Concatenation,将数据集连接起来,不过,union在Concatenation之后,会再做一步排序(以便易于分组)与分组,以取出唯一,比较消耗资源。
4)并行计算:Parallelism:当sqlserver发现某个要处理的数据集比较大,cost比较高时,若服务器有多个cpu,sqlserver就会尝试使用
并行的方法,将一个数据集分成若干个,由若干个线程同时处理.

—————————————-参数化问题———————————————————
参数问题
调用存储过程时,执行计划会重用,但因数据的不同,传入不同的数据,可能会造成现有执行计划不符合实际,造成效果慢,此时用
sql构造反而快的结果出现。
1,存储过程的参数分为两类:1,是传入参数,2是内部参数
1,传入参数,若执行过程的执行计划与拿出来执行得到的执行计划不同,可能就发生了参数化问题,比如第一次执行时是nested loop,
执行计划缓存起来,下次查询的数据范围很大,应用hash join的,但因重用了执行计划,仍用nested loop 执行。由此知,参数问题只会
发生在一些表格里的数据分布不均匀,或者用户传入的参数很不均匀的情况下,如:大部分客户查询的是一天的数据,但有一个查一年的
数据就会出现问题,常见的是该用hash join的用了nested join.
解决之道:1)动态sql执行。
2)强制重新编译:
(1)存储过程级:with recompile :在创建存储过程时加入,那么整个存储过程会实时编译,效率低一些。
(2)语句级:option(recompile):在语句后加入,比较精细,只有加了这个语句的sql才会重新编译执行计划,整个存储过程不会重新编译,故效率会高一些,
并且如果有if else,并用没有经过此语句,也不会重新编译。

2,对入内部参数,是在执行过程时才能得到的,在编译时并不知道它的大小,会根据表格数据量预估一个中间值,性能不是最好也不是最坏。For example, consider a column X, containing 10 rows
with values 1, 2, 3, 3, 3, 3, 3, 4, 5, 5. The optimizer would always estimate that a "WHERE
X=value" query will return 2 rows (total number of rows divided by number of distinct
values)

—————————————总结—————————————————————————–
查看执行计划
SET statistics profile on
1)比较rows与estimaterows是否差别较大,
若较大,原因是1)统计信息不对,这时可通过重建索引来更新统计信息。(重建索引的好处:1,更新了统计信息,执行计划预估更加正确,2,处理了数据碎片,查找速度提升。)
2)Executes若Executes值很大,又发生在nested loop中,不适合自己的执行计划,多发生在存储过程中,此时要强制重新编译 option(recompile)
3)查看totalsubtreecost开销,该建索引建索引。
4)若是扫描而不是查找,原因是lookup查找主键开销很大,不如直接扫描来得快,此种情况下看能否消除select中的字段数,避免lookup。
5)清空缓存:dbcc freeproccache