【问题标题】:SQL Server non-clustered index scan or index depending on valueSQL Server 非聚集索引扫描或索引取决于值
【发布时间】:2020-09-10 02:17:57
【问题描述】:

我有一个包含大约 40 列的 SQL Server 表。为了提高查询性能,我创建了一个非聚集索引,其键列为Datetime 类型,包含表的所有列:

CREATE NONCLUSTERED INDEX [IX_index_date] ON [dbo].[MyTable]
(
    [datecolumn] ASC
)
INCLUDE([column1],[column2],...,[column40])

如果我使用显示执行计划的选项运行这样的查询:

SELECT TOP 1 * FROM MyTable WHERE datecolumn > '2019-12-18 00:00:00.000'

有时执行程序使用index seek(相当快,几秒钟),有时它使用index scan(可能需要几分钟)。唯一的区别似乎在于日期的“年龄”。像示例这样的查询总是使用index scan。但是这个查询:

SELECT TOP 1 * FROM MyTable WHERE datecolumn > '2020-01-18 00:00:00.000'

始终使用index seek。我不明白为什么像这样的条件变化最终会导致搜索或扫描。

我怀疑可能没有足够的信息来检测真正的问题,但是,谁能指出这种行为的根本原因?

【问题讨论】:

  • 你能分享两个实际的执行计划吗? brentozar.com/pastetheplan
  • 执行计划有没有查找操作符? (如果索引覆盖,则不应这样做,但请检查此)。表是否分区?无论如何,您显然错过了一些重要信息,因为从索引搜索中选择前 1 不应该花费“几秒钟”,所以我认为您的实际查询比显示的更复杂
  • @MartinSmith 感谢您的评论。我只是仔细检查了一遍。执行计划没有任何查找运算符(我认为这是因为我包含了索引上的所有列)。此外,该表未分区。该查询与我分享的完全一样。 SQL Server 实例在 Azure(标准 S4)上运行
  • 你需要分享执行计划,然后如果你想要一个真正解释它的答案

标签: sql-server


【解决方案1】:

引擎似乎没有考虑到您的TOP 1(因为没有 TOP 1,扫描对于旧日期可能更有效,因为它将返回更多行)。

原因是您的查询中没有ORDER BY。没有ORDER BYTOP 1 非常令人困惑。

SELECT TOP 1 * FROM MyTable WHERE datecolumn > '2020-01-18 00:00:00.000' ORDER BY datecolumn 

【讨论】:

  • 谢谢@Wouter。解决了,尽管我仍然不明白“order by”产生差异的根本原因。我的意思是,索引中的日期不是已经订购了吗?为什么我需要包含“order by”?
  • SQL Sever 将考虑TOP 1,除非使用跟踪标志/查询提示来抑制行目标。它也没有发现它“非常令人困惑” - OP 没有向我们展示其他一些事情
  • 没有 ORDER BY 的 TOP 1 没有多大意义。即使您有日期索引,也不能保证返回第一个日期。这就是为什么你应该添加订单。
  • 是的,我同意这一点。但你说这是性能差异的“原因”
【解决方案2】:

sql server 根据统计信息决定是否查找索引。在示例中,您使用 * 从表中获取所有列。前提是索引中包含的所有列(这不是一个好习惯)总是有一些开销来寻找索引,因此当您扩大谓词范围时,sql server 决定全面扫描索引。

【讨论】:

    猜你喜欢
    • 2015-01-27
    • 1970-01-01
    • 2012-10-01
    • 1970-01-01
    • 2019-08-26
    • 2014-12-18
    • 2018-01-19
    • 2018-05-08
    相关资源
    最近更新 更多