SQL Server 2005/8 查询优化提示

Jon*_*ins 13 sql-server-2005 sql-server

我正在考虑教育一个团队编写更好的 SQL Server 查询,并想知道人们对提高性能的最佳提示是什么。

例如,我曾经有一个 DBA,他坚持认为 count(*) 的性能会比 count(1) 差(我不知道她是否正确,或者它是否仍然适用于最新的查询优化器)。

我应该告诉团队尝试并始终使用或避免哪些简单的事情?理想情况下,我正在寻找 (a) 可能产生合理差异和 (b) 直截了当的事情,1 - 2 行说明。

Con*_*lls 13

查询调优 101

虽然我可以给你一些提示和技巧,但查询调优没有灵丹妙药。首先要做的是了解幕后的实际情况。获得一本好书,比如第三本 Guru's Guide 书。

性能不佳的查询往往有两种基本类型:耗时太长的事务性查询,以及耗时太长的批处理作业(或报告)。查询有问题的一个好兆头是查询计划中的单个项目占用了 99% 的时间。

事务性查询

在大多数情况下,性能不佳的事务查询是以下几种情况之一:

  • 缺少索引。您可以在查询计划中看到这一点 - 连接上的大表的表扫描应该非常有选择性(即返回几行)。

  • 查询无法使用索引。如果 where 子句中有 OR 条件,连接计算值或查询中不可 sarg 的某些其他项目,那么您可能需要重新编写查询。简而言之,sargs是可以使用索引来消除行的查询谓词。逻辑与、等式和不等式(>、>=、<、<= 和 !=)都可以使用 sarg。OR 传统上不可 sarg-able。但是,您通常可以通过将意义从 OR 反转为 NOT(foo 和 not bar)类型构造来将 OR 转换为 sarg-able 谓词。

  • 低效谓词。例如,如果您有一个where in引用嵌套子查询,请查看它是否可以重写where exists为连接或连接。这可能会产生更高效的查询计划,您也可以尝试以下其他标准重写。同样,Guru 的指南和其他有关该主题的书籍是一个很好的起点。

批量查询

批量查询更复杂,并且有不同的调优问题。一些提示是:

  • 索引。由于与事务查询相同的原因,这可能会产生很大的不同。通常,缺少索引的一个好兆头是一个漫长的、磨砺的操作(查询计划的 99%),它似乎并没有使机器崩溃。

  • 临时表。您可能会发现将查询分解为多个填充临时表的查询会更好。更大的查询给了优化器更多的空间来搞砸,尽管这不像以前那样是一个问题。制作临时表,select into因为此操作的日志记录最少(日志活动少得多),从而减少了 I/O 负载。

    请注意,tempdb 中的临时表与优化器用于存储中间连接结果的数据结构相同,因此这样做不会降低性能。您还可以在临时表上创建索引(包括聚集索引和覆盖索引),这可能会提高读取它的查询的性能,原因与它们改进静态表上的查询的原因相同。

    但是不要过度使用临时表,因为它们会使事情更难通过查询进行追溯。对于存储过程中的较小表,请测试以查看表变量是否有帮助。这些是内存中的数据结构,因此它们可以提高性能。

  • 聚集索引和覆盖索引。这些可以提高查询的性能,因为它们会根据某些分组列强制引用磁盘上的局部性。聚集索引可以对批处理作业的性能产生很大的影响。

  • 低效谓词。这些可能会导致 sargs 和其他子优化问题的问题,其方式与事务查询的方式大致相同。

  • 表扫描是您的朋友。与流行的看法相反,表扫描本质上并不邪恶。通常,它们是事务查询中出现问题的标志,但它们通常是执行大批量操作的最有效方法。如果您正在处理表中超过百分之几的行,则表扫描通常是覆盖该表的最有效方法。

  • 嵌套循环连接。看看优化器在连接的两边做了什么。如果您这样做,这些可能效率低下(例如,表扫描嵌套循环连接两侧的两个大表。考虑使用聚集索引或order by尝试将操作更改为合并连接或暗示促进散列连接,如果一侧是小到可以做到这一点。

锁定

锁定也会导致性能问题。如果您的系统在负载下表现不佳,请查看与锁相关的分析器和性能计数器并检查是否存在任何重大争用。 sp_who2结果集中有一个“BlkBy”列,它将显示查询是否被阻止以及是什么阻止了它。此外,带有“死锁图”事件(如果您有查询死锁)和锁相关事件的配置文件对于解决锁问题很有用。