简介

     在SQL Server中,针对复杂查询使用TOP子句可能会出现对性能的影响,这种影响可能是好的影响,也可能是坏的影响,针对不同的情况有不同的可能性。

     关系数据库中SQL语句只是一个抽象的概念,不包含任何实现。很多元数据都会影响执行计划的生成,SQL语句本身并不作为生成执行计划所参考的元数据(提示除外),但TOP关键字却是直接影响执行计划的一个关键字,因此在某些情况下使用TOP会导致性能受到影响,下面我们来看集中不同的情况。

 

单表情况

    对于单表查询(这里的所说的单表指的是不包含视图、表值函数的物理单表)来说,存在TOP基本不会对性能产生影响,如果在SQL Server中加入了TOP,那么TOP本身可以看作是一个查询提示,意味着告诉优化器“返回结果只有N行”。我们看一个简单的例子,如图1所示:

图1.指定TOP关键字的单表执行计划

 

    由图1执行计划对比可以看出,对于有索引支撑的单表查询来说,使用TOP子句往往可以提升性能,此时TOP N的行数的N则提示查询优化器该查询返回N行,而不是使用统计信息中的数据分布,此时TOP N对于查询优化器来说是合理的。

    但有些时候Grant Memory(每次执行计划生成时会预估所需的内存,如果预估内存小于执行内存,则会spill to tempdb,对性能产生非常大的影响,由于每一个版本预估内存的公式变化极大,因此不在此详细解释了)不准会产生非常高的性能影响。在开始谈这点,之前,我们先谈两个操作符:

Sort

    Sort操作符是非常通用的排序操作符,在执行计划中可能会出现在多个地方,比如Merge Join之前,由于Order By导致的等。该算法非常通用,可以对非常大的结果集进行排序,该操作符是阻塞式(意味着排序结束之前数据无法流动到下一个操作符),并且需要大量内存和CPU资源。该操作符还有一个问题是当Grant Memory不足时,需要TempDB辅助完成排序,因此有极大的性能开销。

Top N Sort

    TOP N Sort是适应小场景,专门针对少量查询的排序算法。对于只选择几条数据来说,对于整个结果集进行排序成本过于高昂,因此TOP N的算法是首先取第一条数据,与其他数据进行对比,看是否最大(或最小),再取第二条数据对比,依次类推,直到找到前N条数据。该算法如果行数较小,则相比SORT操作符性能提升明显,但如果N值过大,则由于下述原因该算法不合适:

1.该算法不支持spill to tempdb,导致无法承载太大的结果集。

2.该算法需要遍历N次,如果N过大,则成本过高。

 

    对于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语句时,可以根据实际情况考虑本文的建议。

SQL Server中TOP子句可能导致的问题以及解决办法的更多相关文章

  1. SQL SERVER中什么情况会导致索引查找变成索引扫描

    SQL Server 中什么情况会导致其执行计划从索引查找(Index Seek)变成索引扫描(Index Scan)呢? 下面从几个方面结合上下文具体场景做了下测试.总结.归纳. 1:隐式转换会导致 ...

  2. SQL Server数据库实例名与服务器名不一致的解决办法

    SQL Server数据库实例名与服务器名不一致的解决办法 --EXEC sp_addlinkedserver --   @server = 'PSHGQ' --GO --select * from  ...

  3. SQL Server中提前找到隐式转换提升性能的办法

        http://www.cnblogs.com/shanksgao/p/4254942.html 高兄这篇文章很好的谈论了由于数据隐式转换造成执行计划不准确,从而造成了死锁.那如果在事情出现之前 ...

  4. SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析

    在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index ...

  5. SQL SERVER中关于OR会导致索引扫描或全表扫描的浅析 (转载)

    在SQL SERVER的查询语句中使用OR是否会导致不走索引查找(Index Seek)或索引失效(堆表走全表扫描 (Table Scan).聚集索引表走聚集索引扫描(Clustered Index ...

  6. SQL Server没有足够的内存继续执行程序 (mscorlib)的解决办法

    在Microsoft SQL Server Management Studio 中执行较大的sql脚本时,会报没有足够的内存继续执行程序(mscorlib)的错误.如下图所示 解决方法: 使用sqlc ...

  7. MS SQL SERVER 2008 R2 实例服务启动出现10048错误解决办法

    由于个人癖好,把MSSQLSERVER服务禁止了开机启动,每次需要的时候就输入CMD命令开启.今天在开启的时候,系统提示“发生服务特定错误:10048”. 于是打开SQL Server配置管理器,发现 ...

  8. SQL Server 没有足够的内存继续执行程序 (mscorlib)的解决办法

    问题: SQL Server 执行大脚本时,出现如下提示信息: 解决方法: 使用 sqlcmd.exe 导入 1.win + r,输入 cmd 进入 C:\Program Files\Microsof ...

  9. Windows 2012 安装 SQL Server 2012,.Net Framework 3.5安装不成的解决办法

    This behavior can also be caused by a system administrator who configures the computer to use Window ...

随机推荐

  1. 2.WindowsServer2012R2装完的一些友好化设置

    网站部署之~Windows Server | 本地部署 http://www.cnblogs.com/dunitian/p/4822808.html#iis 1.桌面图标(控制面板里面屏蔽了,得自己输 ...

  2. Carousel 旋转画廊特效的疑难杂症

    疑难杂症 该画廊特效的特点就是前后元素有层级关系. 我想很多人应该看过或者用过这个插件carousel.js,网上也有相关的教程.不知道这个插件的原型是哪个,有知道的朋友可以告诉我. 该插件相对完美, ...

  3. 9、 Struts2验证(声明式验证、自定义验证器)

    1. 什么是Struts2 验证器 一个健壮的 web 应用程序必须确保用户输入是合法.有效的. Struts2 的输入验证 基于 XWork Validation Framework 的声明式验证: ...

  4. java单向加密算法小结(1)--Base64算法

    从这一篇起整理一下常见的加密算法以及在java中使用的demo,首先从最简单的开始. 简单了解 Base64严格来说并不是一种加密算法,而是一种编码/解码的实现方式. 我们都知道,数据在计算机网络之间 ...

  5. [EasyUI美化换肤]更换EasyUi图标

    前言 本篇文章主要是记录一些换EasyUI皮肤的过程,备忘.也欢迎美工大神各路UI给点好意见,EasyUI我就不介绍了,自行百度吧..(So..所以别问我是不是响应式..本身EasyUI就不是响应式. ...

  6. Hibernate中事务的隔离级别设置

    Hibernate中事务的隔离级别,如下方法分别为1/2/4/8. 在Hibernate配置文件中设置,设置代码如下

  7. JAVA FreeMarker工具类

    FreeMarkerUtil.java package pers.kangxu.datautils.utils; import java.io.File; import java.io.StringW ...

  8. BPM配置故事之案例11-操作外部数据源

    小明:可以获取ERP数据了-- 老李:哦,这么快?小伙子,我非常看好你,来来,别急着走,再陪我聊会-- 小明:--您老人家不是又要改流程吧? 老李:没有没有,哎嘿嘿嘿,我们这不都是为公司效率着想嘛,这 ...

  9. Web API 入门指南 - 闲话安全

    Web API入门指南有些朋友回复问了些安全方面的问题,安全方面可以写的东西实在太多了,这里尽量围绕着Web API的安全性来展开,介绍一些安全的基本概念,常见安全隐患.相关的防御技巧以及Web AP ...

  10. CSharpGL(11)用C#直接编写GLSL程序

    CSharpGL(11)用C#直接编写GLSL程序 +BIT祝威+悄悄在此留下版了个权的信息说: 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharp ...