Sql-Server

我如何有效地處理非常傾斜的數據?統計數據是最新的,但似乎沒有幫助

  • December 19, 2016

我有一張表,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 個使用者,我認為這不會對您構成真正的問題。

有關更多資訊,請參閱:

引用自:https://dba.stackexchange.com/questions/158183