【问题标题】:Full table scan over indexed columns?对索引列进行全表扫描?
【发布时间】:2020-01-10 21:49:16
【问题描述】:

我有以下疑问:

select 
    Table1.Id,
    Table1.SomeColumn1,
    Table1.SomeColumn2,
    Table1.SomeColumn3
    Table2.Id,
    Table2.SomeColumn,
from   
    Table1 
inner join 
    Table2 on Table1.Table2_Id = Table2.Id
inner join 
    Table3 on Table3.Id = Table2.Table3_Id
where  
    Table3.Some_Column = 181715
  • Table1.Table2_Id 已编入索引(非集群)
  • Table2.Table3_Id 已编入索引(非集群)
  • Table3.Some_Column 已编入索引(非聚集)
  • 所有主键都有索引(聚集索引)

尽管如此,查询的性能很糟糕。

查询执行计划如下: https://snipboard.io/Xd67ru.jpg

正如我们所见,数据库引擎正在对 Table1 进行全表扫描,这是完全没有必要的(因为所有连接都在索引列上)。

怎么了?如何改进?

【问题讨论】:

    标签: sql sql-server performance indexing


    【解决方案1】:

    只是一个猜测 - 但我首先要尝试的是使这些索引覆盖,例如添加一些额外的列作为 included 列,以便可以从非聚集索引中满足查询 - 而不是必须使用昂贵的“Key Lookup”返回基表来获取更多列。

    尝试将您的索引更新为:

    CREATE NONCLUSTERED INDEX IX_Table1
    ON dbo.Table1(Table2_Id)    --- create index on foreign key column
    INCLUDE (SomeColum1, SomeColumn2, SomeColumn3);
    
    CREATE NONCLUSTERED INDEX IX_Table2
    ON dbo.Table2(Table3_Id)
    INCLUDE (SomeColumn);
    

    使用这些“覆盖”索引,整个查询(您需要作为结果的所有列)都存在于这些索引的叶级 - 因此只需使用索引查找,就可以“满足”整个查询。这应该避免对基表进行昂贵的键查找,并且可能还会导致“全表扫描”消失。

    试一试!

    【讨论】:

    • 看起来可行。我可以在现有索引上执行此操作,还是应该创建另一个索引?如果我对现有索引执行此操作,是否会影响其他选择的性能?
    • @JakubSzułakiewicz:拥有两个索引没有意义 - 将现有的索引(可能只有索引列)替换为也具有“包含”列的索引
    • @marc_s - 使用inner join's 开始一场关于您的编辑的代码格式化大战怎么样?原文对我来说更具可读性:p
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-04
    • 1970-01-01
    • 2013-01-07
    • 1970-01-01
    • 2016-11-24
    相关资源
    最近更新 更多