设为首页 收藏本站
查看: 663|回复: 0

[经验分享] SQL Server 性能调优4 之书写高效的查询

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2014-7-9 10:03:35 | 显示全部楼层 |阅读模式
限制查询的行和列来提高性能这条规则非常简单,这里就不细说了。
使用搜索可参数化判断(sargable conditions)来提高性能Sargable 由 Search ARGument Able 简写而来,字面意思是搜索可参数化?还是比较晦涩哎...

总之使用Sargable判断可以帮助查询优化器更有效地利用索引,并提高采用 index seek 的可能性,我们先把所有的操作符分一下组。
  • Sargable操作符
    • =
    • >
    • >=
    • <
    • <=
    • BETWEEN
    • LIKE (通配符必须出现在最后,比如‘R%’)
  • 非Sargable操作符
    • !=
    • !>
    • !<
    • <>
    • NOT EXISTS
    • IN
    • NOT IN
    • BETWEEN
    • LIKE (通配符出现在前面,比如'%R')
    • NOT LIKE
    • 针对某列的函数
知道了这些你就可以在允许的场合下尽量使用Sargable操作(譬如用多个 OR 来替代 IN)在判定中巧妙地利用计算操作来提高性能WHERE 子句中针对列的计算操作会导致非Sargable,间接导致列上的索引无法被有效利用,所以应当尽量避免。不幸的是没有什么自动方法来帮助你找到这些地方,你必须手工检查查询脚本并利用性能工具来定位问题所在。
我们用 AdventureWorks2012 数据库中的两张表来做个例子:
  • [AdventureWorks2012].[HumanResources].[Employee]
  • [AdventureWorks2012].[HumanResources].[EmployeePayHistory]
我们第一个查询抽出 Employee 表的基本信息,并取得对应的 EmployeePayHistory 表中最新的数据,并且满足 HourlyRate*8<=152
  • SELECT  
  •   E.LoginID  
  •   ,E.JobTitle  
  •   ,E.BirthDate  
  •   ,E.MaritalStatus  
  •   ,E.Gender  
  •   ,E.HireDate  
  •   ,EP.HourlyRate  
  •   ,EP.RateChangeDate  
  • FROM [AdventureWorks2012].[HumanResources].[Employee] AS E  
  • JOIN  
  • (  
  •   Select  
  •     Max(BusinessEntityID) AS BusinessEntityID  
  •     ,Max(RateChangeDate) AS RateChangeDate  
  •     ,Rate AS HourlyRate  
  •   FROM  
  •     [AdventureWorks2012].[HumanResources].[EmployeePayHistory]  
  •   GROUP BY  
  •     Rate  
  • ) as EP  
  • ON E.BusinessEntityID=EP.BusinessEntityID  
  • WHERE EP.HourlyRate*8<=152  


上面的查询在 WHERE 中进行<=判断前对列进行了一次数字计算(*8),该列上的索引就无法起效了。
对 WHERE 子句稍作修改,就可避免这个问题:
  • ..  
  • ..  
  • WHERE EP.HourlyRate<=152/8  


修改后在 <= 判断前没有对列进行操作,所以列上的索引会起效。看一下前后的性能指标: Center.jpg

前一个查询占用了53%的开销,后一个占用了47%,两者相差数量级虽然不是非常大,但是随着表数据的增加,差异将逐渐扩大。
不在判定中对列进行函数操作来提高性能与前一段的原理一样,WHERE 子句中针对列的函数操作会导致“非Sargable”,导致性能下降。这里就不重复举例了。
利用定义参照的完整性来改善性能定义参照的完整性 (Declarative Referential Integrity),简称 DRI,指利用主键和外键来保证数据库的完整性/一致性。

经常遇到这样的情况:开发者在主表中建立了主键,并用这个主键到子表中去取关联数据,但却没有在子表中建立外键。实际上建立外键不但能帮助你保证数据库的完整性/一致性,还能提高查询关联数据时的性能,我们用一个示例来验证这个说法:
1. 我们新建两张表
  • IF OBJECT_ID('ProductDemo') IS NOT NULL  
  •   DROP TABLE ProductDemo  
  • GO  
  • IF OBJECT_ID('ProductModelDemo') IS NOT NULL  
  •   DROP TABLE ProductModelDemo  
  • GO  
  • select * into ProductModelDemo from Production.ProductModel  
  • select * into ProductDemo from Production.Product WHERE ProductModelID is not null  
  • GO  


2. 在子表 ProductDemo 上声明 ProductModelID 为非空字段,并建立为主键
  • ALTER TABLE ProductDemo  
  • ALTER COLUMN ProductModelID INT NOT NULL  
  • GO  
  •   
  • ALTER TABLE ProductDemo ADD CONSTRAINT [PK_ProductDemo_ProductID]  
  • PRIMARY KEY CLUSTERED  
  • (  
  •   [ProductID] ASC  
  • )  
  • GO  


3. 在主表 ProductModelDemo: 上建立主键
  • ALTER TABLE ProductModelDemo ADD CONSTRAINT [PK_ProductModelDemo_  
  • ProductModelID] PRIMARY KEY CLUSTERED  
  • (  
  •   ProductModelID ASC  
  • )  
  • GO  


4. 执行测试查询
  • SELECT  
  •   P.ProductID  
  •   ,P.ProductModelID  
  • FROM  
  •   ProductDemo AS P  
  • JOIN  
  •   ProductModelDemo AS PM  
  • ON  
  •   P.ProductModelID=PM.ProductModelID  
  • WHERE  
  •   P.ProductID=680  
  • GO  


执行计划如下: Center.jpg


5. 建立子父之间的外间关联
  • ALTER TABLE ProductDemo  
  • WITH CHECK  
  • ADD CONSTRAINT  
  •   FK_ProductDemo_ProductModelDemo_ProductModelID  
  • FOREIGN KEY  
  •   (ProductModelID)  
  • REFERENCES  
  •   ProductModelDemo(ProductModelID)  
  • GO  


再次执行第4步的查询,执行计划如下: Center.jpg

修改后的查询只需要在 ProductDemo 表上执行一次索引检索。
在外键字段上定义 NOT NULL,保证了子表中的数据必在父表中存在关联信息,优化器从而“信任”该子表(在不检索父表数据的情况下,不需要再去访问/检查父表)。
“信任”外键来获取性能改进使用 sys.foreign_keys 系统视图能获取外键的信息,is_not_trusted 字段表示该外键是否被“信任”。
要建立被“信任”的外键可以在创建脚本中使用 WITH CHECK 参数,具体可参照前文的脚本。
备注最后再添加几点:
  • 尽可能多的指定查询筛选条件
  • 可以不用 ORDER BY 尽量不用
  • GROUP BY 子句中的项目尽可能少,并尽可能取自同一个表
  • GROUP BY 子句中尽量用数字类型的字段,避免用文本
  • GROUP BY 和 ORDER BY 中的字段尽量取自同一个表


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-21881-1-1.html 上篇帖子: SQL Server 性能调优3 之索引(Index)的维护 下篇帖子: 无法打开SQL Server的连接
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表