【问题标题】:Get SQL Server to use index seek + key lookup instead of clustered index scan, without WITH (FORCESEEK)让 SQL Server 使用索引查找 + 键查找而不是聚集索引扫描,而不使用 WITH (FORCEEK)
【发布时间】:2011-08-22 04:49:39
【问题描述】:

版本:SQL Server 2008 R2

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

查询:

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 作为搜索谓词时,查询优化器规则和较差的基数估计也会导致优化器执行表或索引扫描操作而不是索引查找。

【问题讨论】:

  • SQL Server 将自动参数化一些查询 - 我不知道具体情况,但是,它可能正在尝试针对任何 LIKE ... 值优化上述内容,因此正在制作此特定搜索的错误计划选择。
  • @marc_s,如果你阅读了这个问题,你可以看到在没有任何查询提示的情况下,查询优化器将选择需要 500 倍以上 IO 的计划。也许它检测到我的磁盘处于空闲状态并渴望工作?这可能是一个很好的理由。无论如何,假设您确实再次阅读了该问题,您可以看到我在寻求一种方法来帮助查询优化器在不使用 FORCESEEK 的情况下选择更好的计划。
  • 我不认为 SQL Server 会查看硬件并确定特定计划是好的,因为硬件当前空闲 - 计划创建成本很高。资源 - 制定计划时通常考虑重用。
  • @Will A,我在讽刺:P

标签: sql-server indexing query-hints


【解决方案1】:

这里的版本展示了“体面”的 IO 数据,而无需诉诸 FORCESEEK。 有趣的是,这个看起来很糟糕的查询表现得“更好”。

免责声明:这对于 'Max%' 和 '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

【讨论】:

  • 谢谢,这行得通。不幸的是,它不是很“对 ORM 友好”。
  • 好吧,使用 SQLAlchemy,没有“不适合 ORM”之类的东西。我已经成功地实现了这一点。再次感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 2020-02-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多