复杂SQL拆分优化

  拆分SQL是性能优化一种非常有效的方法之一,

  具体就是将复杂的SQL按照一定的逻辑逐步分解成简单的SQL,借助临时表,最后执行一个等价的逻辑,已达到高效执行的目的

  一直想写一遍通过拆分SQL来优化的博文,最近刚好遇到一个实际案例,比较有代表性,现分享出来,

  我们来通过一个案例来分析,为什么拆分语句可以提高SQL执行效率,更重要的是弄清楚,拆分前为什么慢,拆分后为什么快了?

  幼稚的话,各位看官莫笑
  

  先看一下相关表的数据量,大表也有5900多万,小表有160多万

  (声明:我从来没认为5000W就是大表,或者说表很大就说明业务或者数据库很牛叉,从来么有。能把大表拆分小表,永远不出现超级大表又能满足业务需求,那才叫牛逼)

  如下是本次优化的SQL语句

  其实SQL称不上复杂,无奈这几个表的数据量都稍微显得有些大,另外里面嵌套比较复杂的业务逻辑,

  历史上经过几轮“高手”的在索引上全方为的优化之后,也能正常运行

  但是随着时间的推移,表中的数据量越来越大,温水煮青蛙一般,SQL越来越慢,越来越慢,

  终于还是暴露了出来,性能问题还是无法被掩盖的,

说实话这么个SQL,分页查询运行超过1分钟(服务器比较稳定,没有什么负载,测试之前博主习惯性rebuild所有索引)

  

  造成上述问题的原因是多样的,业务上的,历史上的,数据上的等等吧,也不用太鄙视了吧,哈哈

  家家有本难念的经,其实不用笑,之前有个同事离职去了一家挺牛逼的上市公司,又一次发微信说卧槽这里的系统还真不如咱们在**公司的系统的,哈哈

  博主所在的公司,也有数千台SQL Server数据库服务器了,动不动超过一两分钟分钟的查询还是有一些的,

  这也是博主能够专职长期优化SQL的原因吧

  因为这种SQL遇到太多了,历任开发人员和DBA也不是吃白饭的,想通过索引来实现质的改变是不可能的
  并不是我不重视索引,或者说我不懂索引,
  我觉得仅仅是通过索引就能优化的SQL语句,或者说建了索引,速度立马上去了几十倍,那只能说明一个问题:这种问题本身就太弱

  当我第一次看到这个SQL执行的这么慢,在了解相关表数据之后,
  第一感觉能否通过拆分,减小SQL连接条件,查询条件的复杂程度,然后再跟其他表join产生最后的结果集,

  

但是如何拆分?先拆分哪个表?怎么组合?这才是问题的本质

  

  举个简单的例子

  比如下面一个查询语句,有四张表join,有多个查询条件,连接条件等等

select A.colName,B.colName,C.colName,D.colName
from TableA A
     inner join TableB B on A.Id=B.Id and A.Type=B.Type and 其它条件
     inner join TableC C on B.Code=C.Code and 其它条件
     inner join TableD D on C.BusinessId=D.BusinessId and 其它条件
where A.BusinessDate>=Date1
      and A.BusinessDate<=Date2
      and A.BusinessStatus=''
      and B.BusinessDate=''
      and C.BusinessDate=''
      and 其他查询条件
      and 其他查询条件order by col1,col2,col3
OFFSET M ROWS FETCH NEXT N ROWS ONLY

  如果是三个表拆分,跟第四个表join,可以通过如下备选方案

可以把ABC join起来加上对应的查询条件,拆分成一个临时表,然后跟D表join,

可以把ABD join起来加上对应的查询条件,拆分成一个临时表,然后跟C表join,

可以把ACD join起来加上对应的查询条件,拆分成一个临时表,然后跟B表join,

可以把BCD join起来加上对应的查询条件,拆分成一个临时表,然后跟A表join,

这里就有一个小技巧,要观察一下三个表加上对应的查询条件结果集的总行数,

比如ABC join是3000条结果集,这3000条结果集跟D表join产生了20w条结果,那么就可以先排除D表,

让ABC join起来加上对应的查询条件,生成临时表,在临时表上建立合理的索引,再跟D表join

也就是说先排除一些产生大结果集的join参与join,其他的表join,得到一个相对较少的临时结果集,

在临时结果集上建立索引,再用这个临时结果集去join其他的表。

这种拆分方式,还有最重要的一步,在临时表上加合适的索引,以最优化临时表与物理表的执行

如果数据量不大,拆分是适得其反的,完全没有必要,但是在数据量越大的时候,效果越明显,

那么这里的拆分后究竟有多明显的效果?

记得之前是多少秒?1分钟3秒,也就是63秒,这里是2秒钟

说实话,这种拆分方式经常用,说实话这个速度的提示是我没有想到的

其实问题到这里才刚刚开始

  为什么拆分之前那么慢,为什么拆分之后又变得这么快?

  执行计划就不细看了,上文说了,这个查询并不缺少索引,也确实用到了索引,但是并不代表,有了索引,用到了索引,就万事大吉了。

  因为查询条件较为复杂,相关的表建立的是复合索引,如果要说索引,就必须说统计信息(statistics),

  对于复合索引,也即两个以上字段的索引,其统计信息的特点是只会维护第一个字段的直方图信息,

  这就决定了SQL Sever在对数据量做预估的时候,有可能出现误差

  我这里有写统计信息相关的知识的,可以参考

  某些多个查询条件的情况下,即便是用到了复合索引,

  SQL Server并不能准确地预估某些条件下数据的行数,如果SQL Server一开始就错误地预测到预期的数据量很小,

  那么后继每一步都无法准确地预测真正数据的大小,也即第一步就错了,导致后面每一步都受到第一步的干扰,

  后面往往会采用Loop join的方式执行,这种方式对于较小的结果集,当然没有问题,如果遇到较大的结果集,就非常低效了

  (见过很多超级复杂,join的表多,很复杂的查询条件,且运行缓慢的SQL,SQL Server往往是以loop join的方式去处理表之间)

  所以我们先拆分出来一个较小的结果集,存放在临时表,

  在第一步的拆分过程中,即便某些情况下无法正确地预估表的行数,因为结果集比较小,采用了Loop join的方式来处理也是没有问题的。

  一旦我们拆分出来一个临时表,对临时表加上合理的索引,再跟其他的大表join,

  由于SQL变得简单了,加上有索引,往往会以高效的方式去执行,性能也就上去了

  那么什么是高效?是不是主观臆断或者说是胡说八道,比如呢?

  比如通过更大的内存授予(Memory Grant),因为结果集大,采用并行运行(这里有写并行相关的,可参考)等等,获取更多的资源从而提高执行效率

  事实上,本文举例的SQL拆分之后的运行,正式因为此,授予更大的内存+并行,才得以高效执行。如图。

  

总结:

  本文通过一个SQL语句的拆分来达到优化的方法,说明在一定情况下,拆分SQL是优化的可选方案。

  当然也不是说,复杂的SQL一定会执行的慢,一定需要拆分,对于多个大表join,如果逻辑简单,可能也会快速的执行

  但是对于那些多个大表join的SQL,尤其是在连接条件,查询条件,索引信息复杂的情况下,如果出现性能问题,可以考虑通过拆分SQL来优化其执行效率

  这个只能说,执行的慢的SQL,通过具体的分析,是可以通过拆分SQL语句生成临时表来解决的。

 

SQL 拆分解决了性能问题,但,更重要的是,一定要弄明白:慢,是为什么慢,快,是为什么快,弄不清楚的话,类似问题还会时不时地让你感到困惑。

理解了本质,才能够游刃有余,更好地掌握SQL Server。

写的不对请各位看官指出,本人还很菜,希望得到大神的指点,谢谢。

转载请注明出处 http://www.cnblogs.com/wy123/p/5712001.html

SQL Server SQL性能优化之--通过拆分SQL提高执行效率,以及性能高低背后的原因的更多相关文章

  1. Sql性能检测工具:Sql server profiler和优化工具:Database Engine Tuning Advisor

    原文:Sql性能检测工具:Sql server profiler和优化工具:Database Engine Tuning Advisor 一.工具概要     数据库应用系统性能低下,需要对其进行优化 ...

  2. SQL Server 2014内存优化表的使用场景

    SQL Server 2014内存优化表的使用场景 最近一个朋友找到走起君,咨询走起君内存优化表如何做高可用的问题 大家知道,内存优化表是从SQL Server 2014开始引入,可能大家对内存优化表 ...

  3. SQL Server ->> Memory Allocation Mechanism and Performance Analysis(内存分配机制与性能分析)之 -- Minimum server memory与Maximum server memory

    Minimum server memory与Maximum server memory是SQL Server下配置实例级别最大和最小可用内存(注意不等于物理内存)的服务器配置选项.它们是管理SQL S ...

  4. SQL执行效率和性能测试方法总结

    对于做管理系统和分析系统的程序员,复杂SQL语句是不可避免的,面对海量数据,有时候经过优化的某一条语句,可以提高执行效率和整体运行性能.如何选择SQL语句,本文提供了两种方法,分别对多条SQL进行量化 ...

  5. [转]SQLServer SQL执行效率和性能测试方法总结

    本文转自:http://www.zhixing123.cn/net/27495.html 对于做管理系统和分析系统的程序员,复杂SQL语句是不可避免的,面对海量数据,有时候经过优化的某一条语句,可以提 ...

  6. SQL执行效率和性能测试方法

    对于做管理系统和分析系统的程序员,复杂SQL语句是不可避免的,面对海量数据,有时候经过优化的某一条语句,可以提高执行效率和整体运行性能.如何选择SQL语句,本文提供了两种方法,分别对多条SQL进行量化 ...

  7. SQL Server索引进阶:第九级,读懂执行计划

    原文地址: Stairway to SQL Server Indexes: Level 9,Reading Query Plans 本文是SQL Server索引进阶系列(Stairway to SQ ...

  8. SQL Server游标 C# DataTable.Select() 筛选数据 什么是SQL游标? SQL Server数据类型转换方法 LinQ是什么? SQL Server 分页方法汇总

    SQL Server游标   转载自:http://www.cnblogs.com/knowledgesea/p/3699851.html. 什么是游标 结果集,结果集就是select查询之后返回的所 ...

  9. SQL Server 2000:提示“未与信任SQL SERVER连接相关连”错误

    在使用“用户模式”登陆SQL Server 2000时提示“未与信任SQL SERVER连接相关连”错误,因为在安装SQL Server时选择“仅Windows”模式,所以所有用户都不可以登陆. 解决 ...

随机推荐

  1. PHP搭建大文件切割分块上传功能

    背景 在网站开发中,文件上传是很常见的一个功能.相信很多人都会遇到这种情况,想传一个文件上去,然后网页提示"该文件过大".因为一般情况下,我们都需要对上传的文件大小做限制,防止出现 ...

  2. 高性能Javascript--脚本的无阻塞加载策略

    Javascript在浏览器中的性能,可以说是前端开发者所要面对的最重要的可用性问题. 在Yahoo的Yslow23条规则当中,其中一条是将JS放在底部 .原因是,事实上,大多数浏览器使用单进程处理U ...

  3. favicon.ioc使用以及注意事项

    1.效果 2.使用引入方法 2.1 注意事项:(把图标命名为favicon.ico,并且放在根目录下,同时使用Link标签,多重保险) 浏览器默认使用根目录下的favicon.ico 图标(如果你并没 ...

  4. 前端常用的WindowsCMD命令

    前面的话   在网上找了一些关于命令提示符CMD的资料,但是很多资料都是把所有的功能罗列出来,大部分都不会用到.所以,自己把常用的CMD命令总结如下,方便查阅 操作类 help 列出所有支持的指令及说 ...

  5. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  6. 就这么漂来漂去---一个毕业三个月的java程序员的裸辞风波

    注:这并不是一篇技术文章,而是记录了我这几个月经历的入职,裸辞,找工作的心路历程,简单介绍一个博主的情况,我是16年毕业生,校招进了一家北京的公司,java开发,和很多年轻人一样,干了一段时间,我发现 ...

  7. “此网页上的某个 Web 部件或 Web 表单控件无法显示或导入。找不到该类型,或该类型未注册为安全类型。”

    自从vs装了Resharper,看见提示总是手贱的想去改掉它.于是乎手一抖,把一个 可视web部件的命名空间给改了. 喏,从LibrarySharePoint.WebPart.LibraryAddEd ...

  8. 免费SSL证书 之Let’s Encrypt申请与部署(Windows Nginx)

    我着着皇帝的新衣,但是你看不见    有一颗愿意等待的心,说明你对未来充满希望.有一颗充满希望的心,那么等待又算什么.人就是在等待与希望中度过,我们永远要对未来充满信心! 读在最前面: 1.本文案例为 ...

  9. hibernate-mapping-3.0.dtd;hibernate-configuration-3.0.dtd;hibernate.properties所在路径

    hibernate-mapping-3.0.dtd 所在路径:hibernate-release-5.2.5.Final\project\hibernate-core\src\main\resourc ...

  10. ASP.NET 中的 Async/Await 简介

    本文转载自MSDN 作者:Stephen Cleary 原文地址:https://msdn.microsoft.com/en-us/magazine/dn802603.aspx 大多数有关 async ...