在SQL Server中,针对复杂查询使用TOP子句可能会出现对性能的影响,这种影响多是好的影响,也多是坏的影响,针对不一样的状况有不一样的可能性。算法
关系数据库中SQL语句只是一个抽象的概念,不包含任何实现。不少元数据都会影响执行计划的生成,SQL语句自己并不做为生成执行计划所参考的元数据(提示除外),但TOP关键字倒是直接影响执行计划的一个关键字,所以在某些状况下使用TOP会致使性能受到影响,下面咱们来看集中不一样的状况。数据库
对于单表查询(这里的所说的单表指的是不包含视图、表值函数的物理单表)来讲,存在TOP基本不会对性能产生影响,若是在SQL Server中加入了TOP,那么TOP自己能够看做是一个查询提示,意味着告诉优化器“返回结果只有N行”。咱们看一个简单的例子,如图1所示:app
图1.指定TOP关键字的单表执行计划函数
由图1执行计划对比能够看出,对于有索引支撑的单表查询来讲,使用TOP子句每每能够提高性能,此时TOP N的行数的N则提示查询优化器该查询返回N行,而不是使用统计信息中的数据分布,此时TOP N对于查询优化器来讲是合理的。oop
但有些时候Grant Memory(每次执行计划生成时会预估所需的内存,若是预估内存小于执行内存,则会spill to tempdb,对性能产生很是大的影响,因为每个版本预估内存的公式变化极大,所以不在此详细解释了)不许会产生很是高的性能影响。在开始谈这点,以前,咱们先谈两个操做符:性能
Sort操做符是很是通用的排序操做符,在执行计划中可能会出如今多个地方,好比Merge Join以前,因为Order By致使的等。该算法很是通用,能够对很是大的结果集进行排序,该操做符是阻塞式(意味着排序结束以前数据没法流动到下一个操做符),而且须要大量内存和CPU资源。该操做符还有一个问题是当Grant Memory不足时,须要TempDB辅助完成排序,所以有极大的性能开销。测试
TOP N Sort是适应小场景,专门针对少许查询的排序算法。对于只选择几条数据来讲,对于整个结果集进行排序成本过于高昂,所以TOP N的算法是首先取第一条数据,与其余数据进行对比,看是否最大(或最小),再取第二条数据对比,依次类推,直到找到前N条数据。该算法若是行数较小,则相比SORT操做符性能提高明显,但若是N值过大,则因为下述缘由该算法不合适:优化
1.该算法不支持spill to tempdb,致使没法承载太大的结果集。spa
2.该算法须要遍历N次,若是N过大,则成本太高。3d
对于SQL Server来讲,这个N是否过大的阈值是100。下面咱们来看一个例子,测试数据和代码如代码清单1所示。
CREATE TABLE TestTop
(id INT,sortkey INT,SOMEvalue CHAR(1000))
DECLARE @i INT =1
WHILE @i<300000
BEGIN
INSERT INTO TestTop VALUES(@i,@i,'a')
SET @i=@i+1
END
CREATE CLUSTERED INDEX PK_id ON TestTop(id)
--test 1
SELECT TOP(100) * FROM TestTop
ORDER BY sortkey
--test 2
SELECT TOP(101) * FROM TestTop
ORDER BY sortkey
代码清单1.测试数据与测试代码
第一个测试为TOP 100,正好使用TOP N Sort的算法,第二个测试为TOP 101,只能使用普通Sort的算法,如图2所示。
图2.TOP 101的SORT须要更多内存,从而致使内存授予不足spill to tempdb
咱们再来看执行时间,因为spill to tempdb的存在,那么执行时间如图3所示。
图3.相差很是大的执行时间
从图3能够看出,执行时间相差很是大。
所以对于TOP的使用来讲,尽可能使用TOP 100之内的数值。
因为TOP语句带有对优化器基数估计的提示功能,所以多表查询时在极端状况下可能致使行数低估从而影响性能。
好比下面如图4的示例查询
图4.使用TOP 1的表接连查询
在这种状况下,因为TOP1的存在使得查询优化器使用1做为估计行数,与实际的行数差别巨大,所以对于这种状况,使用TOP反而可能致使成本更高(虽然咱们看到图4中估计的是0%对比100%,但实际差别巨大),更高的缘由不只仅是优化器估计为1,由于Loop Join只要发现1条就能够马上结束,但上面例子中因为过滤条件选择性太低,致使找到第一条数据的随机查找过多(loop join内表循环是随机IO),成本如图5所示。
图5.使用TOP反而致使性能降低
根本缘由是因为估计行数只有1行,大部分状况下这一行
对于上面这种状况来讲,咱们一般能够有下面集中解决办法:
1.使用提示,因为咱们知道这是因为实际行数远大于估计行数致使,所以咱们能够尝试使用hash join,forcescan等提示。
2.增长where条件,使得返回行数具备更高的选择性。
3.不使用TOP1,而使用TOP 10以上的数字,让估计行数变大,好比图5中的查询咱们由TOP1 变为TOP10,那么执行计划则变为如图6所示。
图6.TOP 10的执行计划
这是因为当行数少时,LOOP JOIN能够更快返回有限的行数,至关于对表加了FAST N提示,但行数增多时,优化器更倾向使用MERGE或者HASH完成操做,在上面返回行极多(选择性低)的极端状况下,会拥有更好的性能,结果如图7所示。
图7.特殊状况下TOP10相比TOP1有更好性能。
所以结合单表的例子,推荐使用TOP关键字时,数字在10到100之间。
本文介绍了TOP关键字在单表和多表条件下可能对执行计划产生的影响,进而影响了查询计划。TOP影响执行计划主要是下面两个方面:
所以在特殊状况下调优TOP语句时,能够根据实际状况考虑本文的建议。