SQL Server 執行計劃利用統計信息對數據行的預估原理二(爲何複合索引列順序會影響到執行計劃對數據行的預估)

 

本文出處:http://www.cnblogs.com/wy123/p/6008477.html html

  關於統計信息對數據行數作預估,以前寫過對非相關列(單獨或者單獨的索引列)進行預估時候的算法,參考這裏。
  今天來寫一下統計信息對於複合索引在預估時候的計算方法和潛在問題。
  本文原形來自因而個實際業務問題,某SQL在利用一個符合索引作查詢的時候,發現始終會出現預估偏差較大的狀況,
  而改變複合索引的列順序,這個預估行數的偏差會發生變化,
  也就是說,Create index idx_index1 ON TableName(col1,col2)與Create index idx_index2 on TableName(col2,col1)
  用徹底同樣的的查詢條件作查詢,兩個索引的執行計劃對其預估的行數是不同的
  究其緣由在哪裏呢?算法

  

  先造一個測試環境:測試

CREATE TABLE TestStatistics
(
    COL1 INT IDENTITY(1,1)  ,
    COL2 INT                ,
    COL3 DATETIME           ,
    COL4 VARCHAR(50)            
)
GO

INSERT INTO TestStatistics VALUES (RAND()*10,CAST(GETDATE()-RAND()*300 AS date),NEWID())
GO 1000000

 

 問題重現spa

首先看一個很是有意思的問題,
在同一張表上,
先這麼建一個索引:CREATE INDEX IDX_COL2_COL3 ON TestStatistics(COL2,COL3)
執行一個查詢,預估爲4127.86
而後DROP掉上面的索引,繼續建立一個索引:CREATE INDEX IDX_COL3_COL2 ON TestStatistics(COL3,COL2)
注意COL2和COL3的順序不一致
繼續執行上面的查詢(查詢條件不變,數據不變,僅僅是索引列順序發生了變化),這一次預估爲2414.913d

 

查詢條件同樣,數據也同樣,爲何改變複合索引列順序會影響到執行計劃對數據行的預估呢?code

 

 

 

 

首先來看第一個索引時候的預估算法:htm

  這個查詢他預估爲4127.86行,以下圖blog

 

  提及來預估,就離不開統計信息,首先來看IDX_COL2_COL3這個索引的統計信息,
  咱們知道,對於複合索引,統計信息中只有前導列的統計數據,也就是說IDX_COL3_COL2這個索引只有COL2這個列的統計信息,以下截圖
  對於COL2=2的統計信息,統計爲100336行,咱們記住這個數字索引

 

 

  統計信息的另一個特色就是在會在查詢列(非索引列)上自動建立統計信息,以下截圖
  查詢執行過程當中,自動建立了一個名字爲:_WA_Sys_00000003_24E8431A的統計信息
  這個統計信息就是對COL3列的統計,能夠發如今大於等於2012-10-20以後的統計行數get


  在SQL Server 2012中,對數據行的預估計算方式是各個字段的選擇性的乘積,
  假如Pn表明不一樣字段的密度,那麼預估行數的計算方法就是: 預估行數=p0*p1*p2*p3……*RowCount
  能夠利用這個算法,計算目前數據下,預估出來的結果:4217.86,跟執行計劃預估是一致的,很是完美!

 

 

 

    當刪除了IDX_COL2_COL3重建創建順序爲COL3+COL2的索引的時候,預估以下

   與上面一樣的查詢條件,預估爲2414.91行

 

   

  依據上面的分析步驟,首先來分析索引列上的統計信息,以下截圖爲大於等於2016-10-20以後的預估行數

 

 

同理,本次查詢也會自動創建COL2列上的統計信息(IDX_COL2_COL3索引被刪除),觀察這個統計信息對COL2=2的預估爲83711.36行

   

   一樣咱們利用上述公式,來計算預估的行數:2414.9035行,也很是完美地吻合和執行計劃預估的結果

   

 

  至此,應該很清楚一開始的問題了,就是爲何複合索引列順序不一致,在查詢的時候致使預估也不一致的緣由。
  最根本的緣由有就是:
  符合索引上只有前導列的統計信息,查詢引擎會根據須要自動建立非前導列的統計信息,
  可是,很是關鍵一點,若是細心的話,你會發現查詢引擎自動建立的統計信息的取樣行數都不是100%取樣的,這一點很是關鍵
  正是由於非前導列取樣有必定的偏差,致使在預估算法的時候,也即 預估行數=p0*p1*p2*p3……*RowCount的時候,密度值是不同的
  也即在建立IDX_COL2_COL3的時候,統計出來的COL2密度爲P1_1,COL3密度爲P2_1
  建立IDX_COL3_COL2的時候,統計出來的COL2密度爲P1_2,COL3密度爲P2_2,由於P1_1<>P1_2,P2_1<>P2_2
  所以,計算出的結果就是P1_1*P2_1<>P2_1*P2_2,原理很簡單,但願看官能明白。

  

 

  照這麼計算,對於兩個順序不一樣的統計信息,若是P1_1=P2_1而且P2_1=P2_2,那麼乘積就是同樣的,預估行數也就是同樣的,那麼是否是呢?

  


  對於不一樣順序的兩個索引,先看COL2,COL3順序的索引
  在查詢一次以後(創建了統計信息),執行一個百分之百取樣(WITH FULLSCAN)的統計信息更新
  從新來看其預估行數,這一次預估爲:2894.49

  

 

 

   刪除COL2,COL3順序的索引,創建COL3,COL2爲順序的索引
  在查詢一次以後(創建了統計信息),執行一個百分之百取樣(WITH FULLSCAN)的統計信息更新
  從新來看其預估行數,這一次預估爲:一樣爲2894.49,是吻合上述算法

 

 

 

 總結:

  文本簡單演示了執行計劃利用統計信息預估的算法和原理,以及在計算預估行數時候可能受到的干擾因素,
  這就要求咱們在創建索引的時候,不只僅是說我建一個複合索引就完事了,也要注意其索引列的順序對執行計劃預估的影響,
  更重要的是,要注意查詢引擎自動生成的統計信息對預估的影響程度。

  拋開統計信息談索引的,都是耍流氓。拋開統計信息取樣百分比談統計信息的,也是耍流氓。

  

  引伸出來另一個問題:維護統計信息的時候,能只更新索引列的統計信息,忽略非索引列的統計信息嗎?

 

本人技術能力還很菜,寫的不對的地方還請各位看官指出,謝謝。

相關文章
相關標籤/搜索