並行計劃選擇
我有一個奇怪的查詢計劃問題。我有兩個數據庫(我們稱它們為 DB1 和 DB2),它們都位於同一個 SQL-Server 實例中並且具有相同的模式。在那裡,我們有幾個表,**
dbo.CostCard
其中有 43258326 行,而dbo.CostType
**150 行用於兩個數據庫。過去幾週我們一直在針對 DB1 進行一些應用程序測試。作為這些測試的結果,兩個表的數據都發生了變化。目前table
dbo.CostCard
增加到43379268(增加120942行),tabledbo.CostType
增加到199(增加49行)。我們還實施了一種維護策略,該策略使用邏輯根據碎片重新組織/重建索引,並且如果數據已更改,還會更新統計資訊,我們正在使用全掃描進行更新。目前,只有 DB1 具有此維護常式設置,我們注意到兩個表的統計資訊和索引都已正確更新。到目前為止,一切都很好!
現在奇怪的部分來了。我們有一個相當簡單的聲明,我們注意到性能下降很大。這是聲明:
SELECT DISTINCT TOP 100 n1t1.Description FROM CostCard AS n0t0 JOIN CostType AS n1t1 ON ( n0t0.CostType ) = ( n1t1.Code ) WHERE ( ( n1t1.Description ) LIKE ( '%legal research%' ) ) AND ( ( n1t1.Description ) IS NOT NULL ) ORDER BY n1t1.Description
我們注意到查詢優化器正在為 DB1 創建一個串列計劃(我們已經重新編譯了很多次),我們知道統計數據和索引正在定期更新,並且正在使用一個並行計劃(更好的計劃,是的,我們已經重新編譯了很多次)對於過去幾個月一直閒置的 DB2 !!!
這怎麼可能?在過去的幾周里,我一直試圖弄清楚這一點,但已經沒有想法了。有人可以在這裡闡明一下嗎?
PS:我附上了一個包含所有資訊的壓縮文件,包括查詢計劃和統計資訊。
https://dl.dropboxusercontent.com/u/72497299/Terrible%20Bad%20Query%20Plan.zip
謝謝,真的,真的很感謝任何幫助!!!
從 SQL Server 查詢優化器的角度來看,在這種情況下,並行和串列執行計劃之間沒有太多選擇。
一般來說,優化器的成本模型會降低並行計劃中運算元的 CPU 成本(而不是 I/O 成本),這與估計的可用並行度成比例。這種 CPU 調整解釋了為什麼優化器會選擇並行計劃(通常會消耗更多資源)而不是串列計劃。
不幸的是,成本模型沒有將這種 CPU 減少應用到嵌套循環 join 的內側。這對我來說毫無意義(因為內側仍然有效地使用並行性),但我沒有設計成本模型。
無論如何,由於此執行計劃中的大部分 CPU 成本與聚集索引掃描相關(不適用 CPU 減少),因此串列和並行之間的選擇很接近。從廣義上講,要被選中,並行計劃必須使用本地/全域流聚合來節省足夠的費用,以補償額外的交換(分發和收集流)。該決策所涉及的成本敏感地取決於行值的分佈以及行數。由於相對較少的行和低 CPU 運算符,權衡可以很容易地採取任何一種方式。
簡而言之,這個查詢受到了應用於並行嵌套循環連接成本計算的有爭議的設計選擇的影響。您可以使用計劃指南或使用未記錄的跟踪標誌 8649強制選擇並行計劃。在 SQL Server 2016 SP1 CU2 及更高版本中,您還可以使用未記錄的
ENABLE_PARALLEL_PLAN_PREFERENCE
提示。
不同的數據庫如何使用不同的查詢計劃?這完全取決於設置的選項、統計資訊、查詢、索引等。我無法開始向你解釋。
我建議你做的是,如果你知道它應該使用的計劃,你可以給出查詢提示(通常是一個壞主意)或者你可以重寫你的查詢。首先,您確實知道“IS NOT NULL”不是必需的。去掉它。此外,在點“贊”時,最好將百分號放在末尾,例如“法律研究%”。
此外,您真的不需要在這裡加入。你只需要得到一個存在…
你的“來自”表應該是你真正想要得到的。您想獲得 CostType 描述,是嗎?所以讓我們從這裡開始……
SELECT Ct.Description FROM CostType ct WHERE EXISTS (SELECT 1 FROM CostCard cc WHERE cc.CostType = ct.Code) AND Ct.Description like 'Legal Research%'