让SQL Server使用索引查找+键查找而不是聚集索引扫描,而不使用WITH(FORCESEEK)

时间:2011-05-10 06:09:50

标签: sql-server indexing query-hints

版本:SQL Server 2008 R2

数据库:来自http://msftdbprodsamples.codeplex.com/releases/view/55926的AdventureWorks 2008R2

查询:

SELECT TOP 10
    *
FROM
    Person.Person --WITH (FORCESEEK)
WHERE
    LastName like 'Max%'
    OR EXISTS (
        SELECT
            1
        FROM
            Person.PersonPhone
        WHERE
            Person.PersonPhone.BusinessEntityID = Person.Person.BusinessEntityID
            AND Person.PersonPhone.PhoneNumber LIKE '122%'
    )
ORDER BY Person.Person.BusinessEntityID DESC


没有任何查询提示,SQL Server将使用聚合索引扫描,这是IO密集型:

Table 'PersonPhone'. Scan count 14170, logical reads 28446, physical reads 15, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Person'. Scan count 1, logical reads 2844, physical reads 3, read-ahead reads 3215, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


使用WITH (FORCESEEK)查询提示,SQL Server将选择索引搜索+键查找,这样可以更快地完成,并且对IO来说是500倍的更好:

Table 'Person'. Scan count 1, logical reads 59, physical reads 22, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'PersonPhone'. Scan count 1, logical reads 2, physical reads 2, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.


我的问题是,有没有办法让SQL Server在没有任何查询提示的情况下使用更好的计划?也许添加索引?或者更改配置参数?或者SQL Server的查询优化器是否无能为力?

这是来自http://msdn.microsoft.com/en-us/library/bb510478.aspx的宝石:

  

查询优化器规则和差基数估计也可能导致优化器执行表或索引扫描操作,而不是在查询使用IN或LIKE作为搜索谓词时执行索引查找。

1 个答案:

答案 0 :(得分:4)

这是一个展示“体面”IO数据而不诉诸FORCESEEK的版本。 有趣的是,这个看起来很可怕的查询表现得更好。

免责声明:对于“最大%”和“122%”,这可能会表现得更好,但如果将计划重新用于“M%”和“%”,它将如何表现......

SELECT TOP 10 *
FROM Person.Person P
INNER JOIN (
SELECT BusinessEntityID
FROM    Person.Person --WITH (FORCESEEK)
WHERE    LastName like 'Max%'    

UNION

SELECT BusinessEntityID
FROM    Person.Person --WITH (FORCESEEK)
WHERE    EXISTS (        SELECT            *        FROM        
    Person.PersonPhone        WHERE            Person.PersonPhone.BusinessEntityID = Person.Person.BusinessEntityID            AND Person.PersonPhone.PhoneNumber LIKE '122%'    )
) NOTNICE
ON NOTNICE.BusinessEntityID = P.BusinessEntityID
ORDER BY P.BusinessEntityID DESC