【问题标题】:SQL Server Execution Plan issueSQL Server 执行计划问题
【发布时间】:2017-03-05 09:23:04
【问题描述】:

我有两张桌子

CREATE TABLE [dbo].[T2] (
    [Id] INT            IDENTITY (1, 1) NOT NULL,
    [F1] NVARCHAR (100) NULL,
    [F2] NVARCHAR (100) NULL,
    [F3] NVARCHAR (MAX) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

GO
CREATE NONCLUSTERED INDEX [IX_T2_F1_F2]
    ON [dbo].[T2]([F1] ASC, [F2] ASC);

CREATE TABLE [dbo].[T3] (
    [Id] INT            IDENTITY (1, 1) NOT NULL,
    [F1] NVARCHAR (100) NULL,
    [F2] NVARCHAR (100) NULL,
    [F3] NVARCHAR (MAX) NULL,
    PRIMARY KEY CLUSTERED ([Id] ASC)
);

GO
CREATE NONCLUSTERED INDEX [IX_T3_F1_F2]
    ON [dbo].[T3]([F1] ASC, [F2] ASC)
    INCLUDE([F3]);

这些是我的执行计划

问题是为什么查询#2的执行计划不是Index Seek (NonClustered),为什么查询优化器选择在PK上扫描聚集索引,而不是非聚集索引{F1,F2}

更新 #1:

【问题讨论】:

  • 这些表中可能有 0 行,所以没关系。在其中放入一百万行并更新您的统计信息。
  • @ta.speot.is 我在两个表中都有 100k 行
  • 你的执行计划中的那些箭头很窄 - SQL Server 估计有多少行?
  • 另外,IX_T2_F1_F2 不包括 F3,因此任何索引查找都将跟随一些其他操作(键查找、聚集索引查找)以获取 F3,SQL Server 可能估计它更快扫描聚集索引而不是 seek + (key lookup/seek)
  • @ta.speot.is 是的,我考虑过了,谢谢。

标签: sql sql-server sql-server-2008 sql-server-2016


【解决方案1】:

SELECT [F1],[F2],[F3] FROM [T2] WHERE ... 需要三列,而IX_T2_F1_F2 只包含其中两列。

SQL Server 有时在覆盖未覆盖它需要的所有列的索引时会很顽固。为了满足查询,它必须结合使用覆盖索引和聚集索引,并且(简化一点)涉及的操作越多,查询成本就越高。

它估计扫描一个索引(聚簇索引)比使用两个索引更便宜,并且您获得了一个包含聚簇索引扫描的计划。

Here 是一篇进一步讨论它的文章,SQL Server 将在什么时候将覆盖索引与聚集索引结合使用。

【讨论】:

  • 我隐约记得 Brent Ozar 有一篇更好的文章,关于覆盖索引以及为什么有时会忽略它们,但我找不到。
【解决方案2】:

您的统计信息可能不是最新的。您可以使用查询提示来强制 SQL Server 使用您的首选索引,例如 with(index(your_index_name))。我建议尝试使用此查询提示来检查索引的性能。

【讨论】:

    猜你喜欢
    • 2017-11-22
    • 1970-01-01
    • 2011-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-30
    • 2011-04-12
    • 2021-12-09
    相关资源
    最近更新 更多