【问题标题】:Why would the addition of an index in SQL Server slow a query, when that index is not used in the plan?当计划中未使用该索引时,为什么在 SQL Server 中添加索引会减慢查询速度?
【发布时间】:2018-02-27 21:54:59
【问题描述】:

我被难住了。如果我删除查询未使用的索引,则查询将从 46 秒缩短到 6 秒。

这里是查询:

SELECT TOP (10) 
[Extent1].[alarm_class_id] AS [alarm_class_id], 
[Extent2].[domain_id] AS [domain_id], 
[Extent3].[description] AS [description], 
[Extent1].[list_id] AS [list_id], 
[Extent2].[list_source] AS [list_source], 
[Extent1].[list_detail_id] AS [list_detail_id], 
[Extent1].[plate] AS [plate], 
[Extent1].[notes] AS [notes], 
[Extent1].[locale_id] AS [locale_id], 
[Extent1].[end_date] AS [end_date], 
[Extent2].[eoc_list_id] AS [eoc_list_id], 
[Extent2].[list_type_id] AS [list_type_id]
FROM   [dbo].[list] AS [Extent2]
INNER JOIN [dbo].[ron_list_detail] AS [Extent1] ON [Extent1].[list_id] = [Extent2].[list_id]
INNER JOIN [dbo].[domain_lookup] AS [Extent3] ON [Extent2].[domain_id] = [Extent3].[domain_id]
WHERE ([Extent2].[domain_id] IN (7)) AND (([Extent1].[end_date] IS NULL) OR ([Extent1].[end_date] > (SysDateTimeOffset())))

这是索引:

CREATE NONCLUSTERED INDEX [ron_CI_list_detail-list_id-plate] 
ON [dbo].[ron_list_detail] ([list_id] ASC, [plate] ASC)
         WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, 
               SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, 
               ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO

附加信息:除非我提供提示,否则查询计划不会使用此索引。如果我提供提示,查询将在一秒钟内完成。

我很困惑 - 想法? (会显示查询计划,但我不知道如何粘贴图像)

【问题讨论】:

  • 我能想到神秘的原因。例如,由于有了索引,可以获得额外的统计信息。然而,这些信息会导致错误的查询计划。
  • 我只能说,“它发生了”。我有一个特定的查询,我必须在其中包含一个提示,因为如果我不这样做,它的运行速度会慢 100 倍。除非我删除了专门为加速特定查询而设计的索引。计划优化器从不自己选择查询,它的存在似乎使它使用了一个可怕的计划。不知道为什么。这只是一次又一次的情况。我认为 999 次中的一个,它本身不起作用,需要手持。唯一的解决方法是包含提示。
  • 如果创建没有 [Plate] 的索引会发生什么情况,如下所示: CREATE NONCLUSTERED INDEX [idx_Test] ON [dbo].[ron_list_detail] ( [list_id] ASC )
  • @pmbAustin - 你在向 T 描述我的情况
  • @MJH - 感谢您的想法。我试过了,但没有运气。我很感激这个想法!

标签: sql sql-server performance indexing


【解决方案1】:

我能想到的原因之一是其他指数的过时统计数据。以下是可能发生的情况:

  1. 您现有的索引具有过时的统计信息,这会欺骗优化器,使其认为它们更适合您的查询。因此,未使用新索引;
  2. 在实际执行查询时,产生的计划会大量丢失,查询需要很长时间才能运行;
  3. 当您通过提示确定索引时,查询优化器别无选择,只能使用它,而且它运行得更快(应该如此)。

优化索引时,确保所有索引都重新构建并更新所有统计信息(不一定使用fullscan,默认模式通常也可以)。很可能,在您执行类似的操作之后

alter index all on [dbo].[ron_list_detail] rebuild;

计划可能会在不需要任何提示的情况下理顺。

另一件事是您的索引对于这个特定的查询看起来不是最优的。我宁愿想到domain_id, list_id,因为plate 列仅作为输出返回,不用于任何连接条件。

【讨论】:

  • 感谢您的信息。事实证明,我的问题与 pmbAustin 留下的评论非常相似。它会运行得更快(6 秒),根本没有任何索引。有了提示 - 将在一秒钟内。有索引无提示,则为 48 秒
  • @RonIsaac,那么你没有尝试重建索引?
  • 对不起,我错过了指定。我们确实重建了索引。它没有帮助。原来是包含 Top 造成了糟糕的计划。 No Top 或 Top >=1192,则运行正常;小 TOP (
  • @RonIsaac,是的,我见过这样的情况。你试过我建议的索引吗?或者更好的是,使用不同的列顺序 - domain_id, list_id - 它应该更适合您的查询。
  • 18 - 我们需要其他领域的索引(抱歉,我应该说明这是问题的一部分 - 只需阅读“如何发布问题”) - 我们将通过使用查看带有提示。实体框架将访问视图(这就是我们将使用视图的原因。实体框架不允许提示)
【解决方案2】:

原来它是查询中的 TOP。

SELECT ... 很快 SELECT TOP (1191) ... 很慢 SELECT TOP (1192) .... 很快

任何数字 = 1192 都很快 没有Top就快了

奇怪!!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-28
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    • 2022-09-30
    • 2017-10-19
    • 1970-01-01
    相关资源
    最近更新 更多