2017-09-14 51 views
1

有一个相当复杂的SQL Server查询,我一直试图优化几个月,尽管多个索引添加(添加覆盖,非聚集索引)和查询重构/更改需要很长时间来执行。没有深入细节,执行计划如下。在这里有什么东西可以跳出来,特别是效率低下或者不好?我摆脱了所有重要的查找,似乎大量使用索引查找,这就是为什么我感到困惑,它仍然需要大量的时间。当查询运行时,瓶颈显然是CPU(而不是磁盘I/O)。非常感谢您的任何想法。艰难的SQL优化

execution plan

+2

你还可以显示你的查询和表/索引结构吗? – Siyual

+2

另外,将实际的XML计划上传到https://www.brentozar.com/pastetheplan/ –

+1

'这里有什么特别低效或坏的东西跳出来吗?'是的。这3个扫描在嵌套循环内部连接.https://i.stack.imgur.com/RrUxh.png –

回答

0

行,所以我做了基于马丁的意见这似乎已经极大地帮助了查询速度的变化。我不是100%肯定的,这是解决方案BC我一直在运行这个很多,有可能这么多的基础数据已经被放入内存,它现在是快速的。但我认为实际上有一个真正的差异。

具体而言,嵌套循环内部的3次扫描是由非常小的表上的子查询引起的,这些表包含一小部分要完全从结果集中排除的记录。从概念上讲,查询是这样的:

SELECT fields 
FROM (COMPLEX JOIN) 
WHERE id_field NOT IN (SELECT bad_ID_field FROM BAD_IDs) 

的想法是,如果一个记录出现在BAD_IDs它不应该被包含在结果中。

我修修补补这个并将其更改为类似:

SELECT fields 
FROM (COMPLEX JOIN) 
LEFT JOIN BAD_IDs ON id_field = bad_ID_field 
WHERE BAD_IDs.bad_ID_field IS NULL 

这是逻辑上是相同的东西 - 它排除了在BAD_IDs任何ID结果 - 但它使用一个连接,而不是一个子查询。即使执行计划几乎相同, TOP操作被更改为树中其他位置的FILTER,但聚簇索引扫描仍然存在。

但是,它似乎运行速度更快!这是预期的吗?我一直认为以我所采用的方式使用的子查询是可以的,并且服务器会知道如何创建最快的(并且大致相同的,几乎相同的)执行计划。这是不正确的?

Thx!

+2

通常我会将所有'NOT IN(SELECT ...)重写为'NOT EXISTS'。曾几何时,查询规划人员可以更好地优化。在更高版本的SQL中,这可能没有任何区别。 –

+0

@ Nick.McDermaid - 它取决于列的可空性。我认为他们不是空的,因为我没有看到原计划中处理可能的空值的额外设备。 https://stackoverflow.com/a/11074428/73226 –

+0

新计划是什么样的? –