代码改变世界

查询优化(1)

2010-06-10 09:53  知行思新  阅读(5590)  评论(0编辑  收藏  举报

--最近在看Inside Microsoft SQL Server 2005:Query Tuning and Optimization一书。其中有一段内容感觉归纳得不错,纠正了我以前的一些错误概念。

对查询我们可以从以下几个方面来考虑进行优化。

重写查询语句

  • 除了尽量避免太复杂的谓词判断,我们还需要尽可能避免使用outer joins,cross apply,outer apply,correlated scalar subqueries(关联标量子查询)或其他太过复杂的子查询。
  • 在某些情况下,把查询中的非关联标量子查询分离为一个独立的查询,并把此独立查询的结果保存在一个变量中供后续查询使用将会对整个查询的性能有所帮助。这样做还可能对使用并行执行计划带来帮助。
  • 尽量避免在并行执行计划中使用dynamic index seeks动态索引查找。

注:什么是Dynamic Index Seeks

比较以下2个查询的执行计划,其中第2个查询使用了Dynamic Index Seeks

--在Northwind中测试
--查询1
SELECT [OrderId]
FROM [Orders]
WHERE [ShipPostalCode] IN (N'05022', N'99362')

--查询2
DECLARE @SPC1 nvarchar(20), @SPC2 nvarchar(20)
SELECT @SPC1 = N'05022', @SPC2 = N'99362'
SELECT [OrderId]
FROM [Orders]
WHERE [ShipPostalCode] IN (@SPC1, @SPC2)
  • 尽可能使用inline table-valued functions(内联表值函数)代替multistatement TVFs(多语句表值函数)。特别应避免对参数化的多语句表值函数进行cross apply。
  • 尽可能使用基于集合操作的查询,避免使用游标。

优化Schema

  • 如果对于一个高选择性的谓词,执行计划仍使用索引扫描或表扫描,我们应考虑增加一个合适的索引来使优化器使用索引查找。对于使用nested loops join的查询,可考虑给连接的内层表加上合适的索引。一个执行计划如果由于含有bookmark lookup而开销很大时,可以考虑通过增加一个索引来覆盖所有需要取出的列。
  • 如果查询计划中的merge join或stream aggregate之前有sort运算符,我们可以考虑增加一个索引来提供需要的排序。如果有可能的话,尽量创建一个唯一索引或约束,这样优化器会选择使用一对多的merge join代替多对多的merge join。尽可能使创建的唯一索引包含最少的列。
  • 考虑创建合适的外键,NOT NULL和CHECK约束。外键约束能简化连接,把一些outer或semi joins转化为inner joins(或把一个full outer join转化为一个left或right outer join)。Check约束也能减少一些多余的谓词。
  • 尽可能避免把两张表中的不同类型的数据列进行连接。特别需要避免主键和外键的数据类型不符。连接不同类型的数据列可能会使SQL Server无法使用index seeks,降低查询性能,也可能引起语义错误。