2009-09-25 31 views
5

我試圖調試一個相當複雜的存儲過程,跨多個表(10-11)加入。我看到,對於樹的一部分,估計的行數與實際的行數有很大的不同 - 在最差的SQL服務器上,估計返回1行,實際返回55,000行!SQL Server如何計算估計的行數?

我在努力解決這是爲什麼 - 我所有的統計數據都是最新的,而且我已經用幾個表上的FULLSCAN更新了統計數據。我沒有使用任何用戶定義的函數或表變量。據我所見,SQL服務器應該能夠精確地估計將要返回的行數,但是它會繼續選擇一個計劃來執行成千上萬的RDI查找(當它期望只執行1或2)。

我能做些什麼來嘗試和理解爲什麼估計的行數超出了這麼多?

UPDATE:所以在看這個計劃我發現一個節點尤其這似乎suspicous - 使用下面的predecate表上的表掃描:

status <> 5 
AND [type] = 1 
OR [type] = 2 

這個謂詞返回整個表(630行 - 表掃描本身並不是性能不佳的原因),但是SQL服務器的估計行數只有37個。然後,SQL服務器繼續執行多個嵌套循環,並將其轉換爲RDI查找,索引掃描和索引尋找。這可能是我大量失算的根源嗎?我如何得到它來估計更合理的行數?

+0

請問您是否可以發佈您的表定義和完整查詢? – Quassnoi

+0

對不起,但不是真的 - 太大了(250線SP + 10表)。 – Justin

+3

如果您的謂詞完全如此(無括號),那麼您可能有邏輯問題。 AND優先於OR。 應該是[status] <> 5 AND(type = 1 OR type = 2) – GilaMonster

回答

8

SQL Server分裂每個索引成多達200範圍與下列數據(來自here):

  • RANGE_HI_KEY

    顯示直方圖步驟上邊界的鍵值。

  • RANGE_ROWS

    指定有多少行範圍內(他們比這個RANGE_HI_KEY比以前小RANGE_HI_KEY小,但更大)。

  • EQ_ROWS

    指定有多少行正好等於RANGE_HI_KEY

  • AVG_RANGE_ROWS

    每個不同值的行的範圍內的平均數量。

  • DISTINCT_RANGE_ROWS

    指定不同的密鑰值有多少內部這一範圍(不包括RANGE_HI_KEYRANGE_HI_KEY和本身之前前一個關鍵);

通常情況下,人口最多的價值觀進入RANGE_HI_KEY

但是,他們可以進入範圍,這可能會導致分配的偏差。

想象一下這些數據(其他中):行

鍵值計數

1   1 
2   1 
3   10000 
4   1 

SQL Server通常建立兩個範圍:134下一個填充值,這使得這些統計數據:

RANGE_HI_KEY RANGE_ROWS EQ_ROWS AVG_RANGE_ROWS DISTINCT_RANGE_ROWS 
3    2   10000 1    2 

,這意味着當搜索時,例如,2,但有1行,最好使用索引訪問。

但如果3而來的範圍之內,統計是這些:

RANGE_HI_KEY RANGE_ROWS EQ_ROWS AVG_RANGE_ROWS DISTINCT_RANGE_ROWS 
4    10002  1  3334   3 

優化器認爲有3334行的關鍵2和索引訪問是太貴了。

+0

即使使用全面掃描更新統計信息無法解決此問題,我們如何解決此問題? – Meysam

+0

@Maysam:你可以使用'CREATE STATISTICS'作爲你經常使用的謂詞。 – Quassnoi

3

它使用的統計數據,它保持每個索引。

(您也可以創建非索引列的統計信息)

要更新數據庫(警告您在每個表的所有統計信息:將採取非常大的數據庫一段時間不要這樣做在沒有與你的DBA檢查生產服務器...):

exec sp_msforeachtable 'UPDATE STATISTICS ?' 

如果你沒有定期計劃的作業重建最活躍的指標(即手插入或刪除的),你應該考慮你的重建索引(與上面相同的警告適用):

exec sp_msforeachtable "DBCC DBREINDEX('?')" 
0

重建索引可能會解決不正確的估計行值問題