【问题标题】:Why does the optimizer choose a keylookup instead of 2 separate queries?为什么优化器选择一个 keylookup 而不是 2 个单独的查询?
【发布时间】:2019-08-24 18:28:29
【问题描述】:

我有一个表,它在 ID 列上有一个主键/聚集索引,在系统日期列上有一个非聚集索引。如果我使用系统日期列查询表中的所有列(在这里覆盖索引没有意义),执行计划会显示一个键查找,因为对于它找到的每条记录,它必须使用 ID 来获取所有列数据。

奇怪的是,如果我用一个临时表编写 2 个查询,它的执行速度要快得多。我可以查询系统日期以获取 ID 表,然后使用该表搜索 ID 列。这是有道理的,因为您不再对每条记录进行慢键查找。

为什么优化器不为我们做这件事?

--slow version with key lookup
--id primary key/clustered index
--systemdate nonclustered index  

select ID, col1, col2, col3, col4, col5, SystemDate
from MyTable
where SystemDate > '2019-01-01'

--faster version 
--id primary key/clustered index
--systemdate nonclustered index  

select ID, SystemDate
into #myTempTable
from MyTable
where SystemDate > '2019-01-01'

select t1.ID, t1.col1, t1.col2, t1.col3, t1.col4, t1.col5, t1.SystemDate
from MyTable t1
inner join #myTempTable t2
on t1.ID = t2.ID

【问题讨论】:

    标签: sql sql-server query-optimization sql-tuning database-tuning


    【解决方案1】:

    好吧,在第二种情况下,您实际上是在自己进行密钥查找,不是吗? ; )

    由于统计信息过时(或缺失)、索引碎片化,优化器的执行速度可能会变慢。

    要告诉你为什么它实际上更慢,最好粘贴你的执行计划here。这样更容易解释发生了什么。

    【讨论】:

    • 查找的查询计划看起来像下面 Lukasz 的回复中发布的计划。我认为这是问题所在。键查找将执行嵌套循环连接,而如果您像我在上面所做的那样将查询分开,优化器将执行合并/散列连接。我认为这就是密钥查找执行如此缓慢的原因,但我可能是错的。
    • 是的,但是你能把计划粘贴到你使用临时表的地方吗?然后您可以查看它是执行嵌套循环还是合并/散列连接?但是你的建议听起来很适合我。
    【解决方案2】:

    查询优化器选择键查找,因为覆盖索引不支持查询。它必须从表本身中获取缺失的列:

    /*
    --slow version with key lookup
    --id primary key/clustered index
    --systemdate nonclustered index 
    */
    select ID, col1, col2, col3, col4, col5, SystemDate
    from MyTable
    where SystemDate > '2019-01-01';
    

    添加覆盖索引应该会提高性能:

    CREATE INDEX my_idx ON MyTable(SystemDate) INCLUDE(col1, col2, col3, col4, col5);
    

    db<>fiddle demo


    对于没有JOIN的查询:

    select ID, col1, col2, col3, col4, col5, SystemDate
    from MyTable  -- single table
    where SystemDate > '2019-01-01';
    

    执行计划中有JOIN

    引入覆盖索引后,无需额外的键查找:

    【讨论】:

    • 我明白这一点。但是,如果您在一个足够大的组织中工作,所有类型的查询都访问同一个表,那么每次有人抓取的内容不仅仅是索引中的内容时,都在整个表上放置一个覆盖索引是不可行的。我想知道为什么编写为两个单独的查询比使用一个执行键查找的查询要快。
    猜你喜欢
    • 2021-10-25
    • 2019-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    相关资源
    最近更新 更多