2017-09-14 54 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

新計劃是什麼樣的? –