即使通過使其以並行模式執行來改進查詢,查詢性能也會更差
我有一個使用 EFF 從應用程序生成的 SQL 查詢。它使用一個視圖,並且該視圖連接到其中的多個表。查詢執行緩慢,當我查看執行計劃時,我看到查詢是並行執行的(希望這樣,因為它是一個複雜的查詢並且串列執行非常慢,所以故意刪除了串列強制組件)。我也注意到了一些
keylook up
,我早些時候忽略了它,因為該操作的成本看起來很小。現在查詢執行緩慢,並且我創建了覆蓋索引以刪除鍵查找,但即使在此之後計劃使用舊索引並且不使用覆蓋索引。不知道為什麼?這是來自的執行計劃
Paste the plan
。 https://www.brentozar.com/pastetheplan/?id=Bk1YECnOH非常感謝該計劃中任何有助於提高績效的發現。
我查了統計,今天早上更新了,所以不是原因。我正在使用 SQL Server 2016,並在 128GB 中為 SQL Server 分配了 105GB 的 RAM。我相信這已經足夠了。我分配了 10GB 的 tempdb 空間。
除了 keylook 之外,我沒有看到任何其他不良跡象,而且我不是切割和切片執行計劃方面的專家。因此,非常感謝任何幫助。
一件事對我來說很明顯 - XML 查詢計劃中的這個警告:
<Warnings> <PlanAffectingConvert ConvertIssue="Seek Plan" Expression="N'Public'=CONVERT_IMPLICIT(nvarchar(20),[r].[SecurityLevel],0)"/> </Warnings>
SQL Server 中一個鮮為人知的速度殺手是傳遞一個
nvarchar()
參數以用於針對varchar()
索引值的索引搜尋。在這種情況下,SQL Server 所做的是將索引欄位中的每個值轉換為等效nvarchar()
值,並將它們與參數進行比較。為什麼不將
nvarchar
欄位轉換為 avarchar
並使用索引?因為所有的varchar
都是 的子集nvarchar
,但並非所有的nvarchar
都是 的子集varchar
。因此,要進行正確的比較,varchar
必須將值轉換為nvarchar
值。這樣做的效果是索引不用作索引(並且可能根本不使用,具體取決於所需的欄位。)相反,索引從頭到尾掃描以辨識匹配項,每個索引條目都有轉換的值,一一對應。這是非常緩慢的。
有兩種方法可以處理這個問題:
- 將表和索引中的欄位更改為
nvarchar
varchar
(推薦)在查找中使用之前將參數值更改為。可以通過多種方式處理更改。要麼更改被呼叫的儲存過程中的參數類型,更改應用程序傳遞的參數類型(有文章介紹如何為 Entity Framework 呼叫 SQL 做到這一點),或者
CAST/CONVERT
在程式碼中添加呼叫(可能更多麻煩大於它的價值。)
請注意以下圖片
需要注意的最重要的事情之一是,您的估計行數必須與您的實際行數之一,否則,在這種情況下,實施計劃將無法正確選擇正確的運算符。例如,您的估計將返回值 1,而您的實際統計數據會佔用大量行。這可以考慮是因為您的統計資訊更新失敗。
這在以下書中很好地提到了:SQL Server Execution Plans
這麼小的差異不值得擔心,但較大的差異可能表明優化器在選擇計劃時對需要處理的行數進行了不准確的估計,這可能導致計劃選擇不理想。這有很多可能的原因。例如,也許優化器必須為包含 Predicate 的查詢生成一個計劃,該查詢包含缺失或陳舊統計資訊的列,或者優化器可能重用了一個計劃,其中列中的數據量或分佈在統計資訊發布後發生了顯著變化。最後創建或更新。或者,列中的數據分佈可能非常不均勻,使得準確的基數估計變得困難,或者查詢可能包含無法準確估計的邏輯。
參考:SQL Server 執行計劃,第三版,Grant Friitchey
還 :
實際行數——根據執行時統計返回的真實行數。此值在實際計劃中的可用性是這些計劃與記憶體計劃(或估計計劃)之間的最大區別。注意這個值和估計值之間的巨大差異。
Estimated Number of Rows – 根據優化器對相關表或索引可用的統計資訊計算得出。這些對於與實際行數進行比較很有用。
但是非常重要的一點是執行緒之間的工作負載分配。實際上,您需要檢查執行緒之間的這種拆分是否幾乎相同。
不均勻的數據分佈和過時的統計數據是執行緒之間工作負載分佈不均勻的常見原因。此圖顯示了在其中一個表上更新統計資訊後工作負載分佈如何變化。 左側為統計更新前的分佈,右側為更新後的分佈。
參考:Pro SQL Server 內部