我如何有效地處理非常傾斜的數據?統計數據是最新的,但似乎沒有幫助
我有一張表,
dbo.ClaimBilling
有 130,000 行。在此表中,列OperatorID
是 avarchar(max)
並且嚴重傾斜。125,000 行是“user1”,其餘 5000 行被拆分為 6 個其他值,“user2”共有 3 條記錄。上有一個非聚集索引
OperatorID
,聚集索引是主鍵,IDClaimBilling
。我目前有以下查詢:
SELECT DISTINCT IDClaimBilling FROM dbo.ClaimBilling cb INNER JOIN dbo.BillingItem bi ON cb.IDClaimBilling = bi.ClaimID WHERE OperatorID = @operator
無論是什麼值
@operator
,行數的估計值ClaimBilling
都是 ~4000,這與任何值將返回的值都不接近,而且它始終是聚集索引掃描,它不使用operatorID
索引。如果我刪除加入並做SELECT DISTINCT IDClaimBilling FROM dbo.ClaimBilling WHERE OperatorID = @operator
然後它確實使用了
OperatorID
索引,但是無論 的值如何,估計都是錯誤的@operator
,這一次總是估計 ~18,000 左右。我
UPDATE STATISTICS dbo.ClaimBilling WITH FULLSCAN
在執行查詢之前做了一個。即使統計數據確切地知道每個值有多少行,為什麼這些估計值如此錯誤?
我
@operator
在測試中聲明並分配一個值。它最初是程序的一部分,我認為這是問題所在,但在臨時語句中使用時它的行為也是一樣的。該查詢僅在使用者首次登錄時執行,因此每個使用者每天可能只執行幾次。
社區 Wiki 答案由對該問題的評論生成
如果您將查詢
@operator
作為變數執行,SQL Server 無法“嗅探”變數中的值,因此它將使用統計數據的平均密度值來計算估計值。無論您為變數分配什麼值,這個平均值估計值總是相同的。解決此問題的一種方法是使用
OPTION (RECOMPILE)
查詢提示。這將在每次執行時編譯一個新的計劃,該計劃針對當時變數中的特定值進行了優化。這是以每次重新編譯語句為代價的(通常很小)。您還可以模組化程式碼。您可以使用一條
IF
語句並檢查它的值,operatorid
如果它是“user1”,則呼叫一個儲存過程,比如說sp_user1
。如果不是“user1”,則呼叫不同的程序。第一個 sp 將針對“user1”進行優化,另一個針對其餘值進行優化。如果需要,您還可以option (recompile)
在第二個 sp 中使用非“user1”值。它也可能是動態 SQL 的一個不錯的案例。這會將您的
@operator
變數轉換為文字值,並為每個使用者定制計劃。由於該表中只有 7 個使用者,我認為這不會對您構成真正的問題。有關更多資訊,請參閱:
- SQL Server 中的局部變數與參數化儲存過程(影片),作者 Kendra Little