如何解决两个实例中同一数据库上的执行计划不同
我正在为一个神秘的问题而苦苦挣扎: 我在生产中有一个查询,该查询显着降低了他的表现,从几秒钟到两分钟不等。 通过分析执行计划,我发现它莫名其妙地不再在表中的某个字段上使用非集群索引。 我执行了以下所有步骤:
如果我强制查询使用索引(带有查询提示),它会立即完成。 为什么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
表 [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 举报,一经查实,本站将立刻删除。