由于“SELECT *”的聚簇表扫描

Chr*_*uer 7 performance index sql-server nonclustered-index query-performance

我有一个Records包含 100 多列和非常多行的表,以及基于我的访问路径的 5 个字段的非聚集索引:

CREATE NONCLUSTERED INDEX [IX_Records_CustomerID]
ON [dbo].[Records] (
    [CustomerID] ASC, -- int
    [IsInvalid] ASC, -- int
    [IsProcessed] ASC, -- bit
    [IsRejected] ASC, -- bit
    [RecordName] ASC, -- varchar(12)
;
Run Code Online (Sandbox Code Playgroud)

这 5 个字段不包括主键RecordID,它是聚集索引中的列。

这是我性能不佳的查询:

SELECT * FROM Records WHERE CustomerID IN (181, 283, 505)
Run Code Online (Sandbox Code Playgroud)

执行计划显示它执行聚集索引扫描,我理解这是因为我选择了未包含在索引中的列。在 Management Studio 中,我将查询更改为:

SELECT CustomerID, IsInvalid, IsProcessed, IsRejected, RecordName FROM Records 
    WHERE CustomerID IN (181, 283, 505)
Run Code Online (Sandbox Code Playgroud)

并且执行计划显示Index Seek,查询执行时间从44秒下降到2秒。但是,我在应用程序中缺乏自由,无法*仅用我需要并包含在索引中的列替换。

当我被锁定时,有没有办法绕过聚集索引扫描SELECT *

Aar*_*and 7

如果您需要索引未涵盖的输出列,优化器必须做出选择:

  1. 执行表/聚集索引扫描(因此所有列都在那里)
  2. 执行查找,然后执行查找以检索未涵盖的列

它将选择哪种方式取决于多种因素,包括索引有多窄,与谓词匹配的行数等。您可以强制使用FORCESEEK提示进行搜索,但我怀疑它最终会执行相同或更差的性能SQL Server 在您的情况下选择的扫描。

一些选项:

  1. 更改应用程序以运行正确的查询。我首先列出这个是有原因的
  2. 创建一个仅选择您需要的列的视图:

    CREATE VIEW dbo.myview
    WITH SCHEMABINDING
    AS
      SELECT col1, col2, col3 FROM dbo.tablename;
    
    Run Code Online (Sandbox Code Playgroud)

    然后您可以将应用程序更改为SELECT *从此视图。或者您可以更有创意并重命名原始表,并将此视图的名称更改为该表以前的名称。显然,突破性的变化;谨慎行事。

  3. 将所有其他列添加到INCLUDE索引的键或列表中。如果这些是硬编码值并且总是使用的值,您可以考虑过滤索引。

  • 感谢您和@MaxVernon 强调更改查询的重要性。我会从我的同事那里获得支持并实现这一目标。 (2认同)