微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

两个实例中同一数据库上的执行计划不同

如何解决两个实例中同一数据库上的执行计划不同

我正在为一个神秘的问题而苦苦挣扎: 我在生产中有一个查询,该查询显着降低了他的表现,从几秒钟到两分钟不等。 通过分析执行计划,我发现它莫名其妙地不再在表中的某个字段上使用非集群索引。 我执行了以下所有步骤:

  • 检查索引碎片:
  • 重新编译索引;
  • 丢弃的统计数据;
  • 重新创建索引;
  • 重启服务器; 但是没什么。。 每当我启动查询时,执行计划都不会使用索引。

如果我强制查询使用索引(带有查询提示),它会立即完成。 为什么sql server在执行计划中不考虑索引?

为了尝试重现问题,我在另一个 sql server 实例中恢复了相同的数据库: 结果是执行计划认使用索引。

为什么在生产中仍然不使用索引? (硬件配置很好,服务器license是标准版)

查询是:

 SELECT Anagrafiche.[Ragione Sociale],Anagrafiche.IDAnagrafica
 FROM ([Registrazioni Magazzino]
 INNER JOIN Anagrafiche ON [Registrazioni Magazzino].IDCliente = Anagrafiche.IDAnagrafica) 
 INNER JOIN Movimenti ON [Registrazioni Magazzino].RifIDMovimenti = Movimenti.ID
 GROUP BY Anagrafiche.[Ragione Sociale],Anagrafiche.IDAnagrafica,Anagrafiche.Fornitore
 HAVING (((Anagrafiche.Fornitore)=1))
 ORDER BY Anagrafiche.[Ragione Sociale]

正确的执行计划是: Right

right plan

错误的是: Wrong

wrong plan

表 [registrazioni magazzino] 包含大约 980.000 行。字段为[idcliente],索引为[IX_Registrazioni Magazzino_2]

解决方法

[Registrazioni Magazzino] 上的非聚集索引不是覆盖索引,换句话说:有些列仍然需要从通过键查找的聚集索引。

因此编译器需要根据统计来决定是否使用索引并进行key查找;或者,考虑到行数,这些额外的键查找的成本是否不值得,而应该扫描聚集索引。

这是复杂的,因为实际上没有从 [Registrazioni Magazzino] 中选择列,查询已转换为 EXISTS 查询,这就是它的方式应该一开始就写。为 1 的 row-goal/TOP 放置在连接的内侧,因此编译器认为它会快速获得结果,而忽略了执行如此多扫描的巨大成本。

这里的解决方案非常简单:更改非聚集索引以包含 RifIDMovimenti 列。您可以将其作为第二个键列来执行,但我认为 {{ 1}} 列会更好:

INCLUDE

CREATE NONCLUSTERED INDEX [IX_Registrazioni Magazzino] ON [Registrazioni Magazzino] (IDCliente) INCLUDE (RifIDMovimenti) WITH (DROP_EXISTING = ON); 上的索引也会有所帮助。这意味着可以预先过滤 Anagrafiche (Fornitore,[Ragione Sociale]) INCLUDE (IDAnagrafica),并且将从查询中删除 Sort。


关于您的查询的进一步说明:

  • 你应该使用别名,尤其是当你有带空格的表名时(无论如何你应该避免)
  • 如前所述,这实际上应该是一个 Fornitore 查询,没有 EXISTS
  • 简单的非聚合过滤器应该放在 GROUP BY 而不是 WHERE
  • 不需要括号连接,它不会帮助或改变编译器的功能

这些更改不是必需的,但有助于查询理解,也可能有助于优化器。

所以你的查询最好变成这样:

HAVING

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。