1. 程式人生 > >Sql Server優化---統計資訊維護策略

Sql Server優化---統計資訊維護策略


首先解釋一個概念,統計資訊是什麼:
  簡單說就是對某些欄位資料分佈的一種描述,讓SQL Server大概知道預期的資料大小,從而指導生成合理執行計劃的一種資料庫物件

預設情況下統計資訊的更新策略:
  1,表資料從0行變為1行
  2,少於500行的表增加500行或者更多
  3,當表中行多於500行時,資料的變化量大於500+20%*表中資料行數

非預設情況下,促使已有統計資訊更新的因素(包括但不限於下面三種,別的我也沒想起來):
  1,rebulid\Reorg index
  2,主動update statistics
  3,資料庫級別的sp_updatestats

開始問題:

對於大表的更新策略是:資料的變化量大於500+20%*表中資料行數
比如對於1000W資料量的表,資料變化要超過500+1000W*20%=2,000,500之後才能觸發統計資訊的更新,
這一點大多數情況下是無法接受的,為什麼?因為該規則下觸發統計資訊更新的閾值太大,會導致某些統計資訊長期無法更新,
由於統計資訊導致的執行計劃不合理的情況已經在實際業務中屢見不鮮,對於統計資訊的更新已經顯得非常必要

同時,僅僅靠sqlserver自己更新統計資訊,也不一定可靠,因為統計資訊中還要一個取樣行數的問題,這個也非常重要
因為SQL Server預設的取樣行數是有上限的(預設取樣,未指定取樣百分比或者SQL Server自動更新統計資訊時候的取樣百分比),
這個上限值在100W行左右(當然也不肯定,只是觀察),對於超過千萬行的表,這個取樣比例還是非常低的
比如下圖超過3億行的表,更新統計資訊時候未指定取樣百分比,預設取樣才去了84萬行)
據樓主的觀察看,對於小表,不超過500W行的表,預設的取樣比例是沒有問題的,對於較大的表,比如超過500W行的表(當然這個500W行也是一個參考值,不是絕對值)
因此說預設取樣比例是根本無法準確描述資料分佈的。

由此看來,人工介入統計資訊的更新是非常有必要的。那麼如何更新索引的統計資訊,有沒有一種固定的方式?答案是否定的。

首先來看能夠觸發統計資訊更新的方式 

1,Rebulid\Reorg index
  當然Rebulid\Reorg索引只是附帶更新了索引的統計資訊,主要是為了整理了索引碎片,
  對於大表,代價相當大,資料庫的維護策略,沒有一概而論的方法,
  對於較小的資料庫或者是較小的表,比如幾十萬幾百萬的表,每天一個rebuild index都可以,
  但是這種經驗移植到大一點的資料庫上恐怕就不好使了(正如名人的成功經驗不可影印一樣,每個人生活的環境不一樣,不能一概而論)。
  這種Rebulid\Reorg index對資源的消耗以及時間代價上都會相當大,甚至有些情況下是不會給你機會這麼做的。
  比如下面rebuild一個複合索引的耗時情況,僅僅是一個表上的一個索引,就花費了5分鐘的時間
  一個業務複雜的表上有類似這麼三五個索引也是正常的,
  照這麼算下去,如果全庫或者是整個例項下的十幾個庫,每個庫數百張表全部這麼做,要多長時間,代價可想而知
  說不定整都沒整完,維護視窗期的時間就到了,除非資料庫不大(究竟大小的臨界值為多少?個人覺得可以粗略地認為100GB吧),否則是不可以這麼做的。

  因此可以認為:通過重建或者重組索引來更新索引統計資訊,代價太大了,基本上是不現實的。

  


2,update statistics

  正是我想重點說的,因為我這裡不具體說語法了,具體語法就不做詳細說明了,
  簡單來說,大概有如下幾種選擇:
  一種預設方式,另外還可以是全表掃描的方式更新,還有就是是指定一個取樣百分比,如下:

--預設方式更新表上的所有統計資訊
update statistics TableName
--對指定的統計資訊,採用全表掃描的方式取樣
update statistics TableName(index_or_statistics__name) with FullScan 
--對指定的統計資訊,採用指定取樣百分比的方式取樣
update statistics TableName(index_or_statistics__name1,index_or_statistics__name2) with sample 70 percent

  相對於重建或者重組索引,update statistics 也是通過掃描資料頁(索引頁)的方式來獲取資料分佈,但是不會移動資料(索引)頁,
  這是Update Statistics代價相對於Rebuild索引小的地方(即便是Update Statistics的時候100%取樣)
  關鍵在於第三種方式:人為指定取樣百分比,如果取樣百分比為100,那跟FullScan一樣
  如果不用100,比如80,60,50,30,又如何選擇?取樣百分比越高,得到的統計資訊越準確,但是代價越大,取樣越小效率越高,但是誤差的可能性會變大,怎麼辦,這就需要找一個平衡點。
  那麼究竟要取樣多少,既能在更新統計資訊的效率上可以接受,又能夠使得統計資訊達到相對準確地描述資料分佈的目的,
  這是還是一個需要慎重選擇的問題,為什麼?參考:http://www.cnblogs.com/wy123/p/5875237.html
  如果統計資訊取樣百分比過低,會影響到統計資訊的準確性,
  如果過於暴力,比如fullscan的方式掃描,
  參考下圖,一個表就Update了50分鐘(當然這是一個大表,上面有多個索引統計資訊以及非索引統計資訊)。如果有數十張類似的表,效率可想而知
  總之就是,沒有一個固定的方式,資料庫不大,怎麼做問題都不大,資料庫一大,加上維護的視窗期時間有限,要在統計資訊的質量和維護效率上綜合考慮

  

3,資料庫級別的sp_updatestats

  用法:
  exec sp_updatestats
  或者
  exec sp_updatestats @resample = 'resample'

  指定 sp_updatestats 使用 UPDATE STATISTICS 語句的 RESAMPLE 選項。

  對於基於預設抽樣的查詢計劃並非最佳的特殊情況,SAMPLE 非常有用。
  在大多數情況下,不必指定 SAMPLE,
  這是因為在預設情況下,查詢優化器根據需要採用抽樣,並以統計方式確定大量樣本的大小,以便建立高質量的查詢計劃。

  如果未指定 'resample',則 sp_updatestats 將使用預設的抽樣來更新統計資訊。 
  預設值為 NO。

  直接執行exec sp_updatestats更新統計資訊,取樣密度是預設的,
  究竟這預設值是多少,MSDN上說預設情況下是“查詢優化器根據需要採用抽樣”,我想著取樣演算法應該沒那麼簡單粗暴
  目前也不知道具體是怎麼一個演算法或者取樣方式,如果有知道園友的話請不惜賜教,謝謝

4,TraceFlag 2371

開啟TraceFlag 2371之後,統計資訊的變化是根據表做動態變化的,
打破了觸發大表統計資訊更新的當表中行多於500行時,資料的變化量大於500+20%*表中資料行數 閾值
參考:https://blogs.msdn.microsoft.com/saponsqlserver/2011/09/07/changes-to-automatic-update-statistics-in-sql-server-traceflag-2371/

  在下圖中,你可以看到新公式的工作方式,對於小表,閾值仍舊是在20%左右,
  只有超過25000行之後,此動態規則才會被觸發生效
  隨著表中資料行數的增加,(觸發統計資訊變更)的百分比會變的越來越低,
  比如,對於100,00行的表,觸發統計資訊更新的閾值已經降低為10%,
  對於1,000,000行的表,觸發統計資訊更新的閾值已經降低為3.2%。

  

  對於10,000,000或者是50,000,000行的表,觸發統計資訊更新的閾值為少於1%或者0.5%,
  而對於他100,000,000行的表,僅僅要求變化在0.31%左右,就可以出發統計資訊的更新。

  但是個人認為,這種方式也不一定靠譜,雖然開啟TraceFlag 2371之後觸發更新索引統計資訊的閾值降低了,但是取樣百分比還是一個問題,
  之前我自己就有一個誤區,看統計資訊的時候只關注統計資訊的更新時間(跟自己之前遇到的資料庫或者表太小有關)
  對於統計資訊,及時更新了(更新時間比較新)不等於這個統計資訊是準確的,一定要看取樣的行數所佔總行數的百分比

如何有效維護索引統計資訊?

  上面說了,要使獲取相對準確的統計資訊,就要在更新統計資訊時候的取樣百分比,
  對於小表,即便按照其預設的變化閾值觸發統計資訊更新,或者是按照100%取樣更新統計資訊,都是沒有問題,
  對於大表,一定要考慮在其達到預設觸發統計資訊更新的閾值之前人為更新這個統計資訊,但是大表的100%取樣統計是不太現實的(效能考慮)
  取樣百分比越高,得到的統計資訊越準確,但是代價越大,這就需要找一個平衡點,那麼如果更新大表上的統計資訊呢?
  如果是認為干預統計資訊的生成,就要考慮兩個因素:一是資料變化了多少之後更新?二是更新的時候,以什麼樣的取樣來更新?
  我們知道,一個表的資料變化資訊(增刪改)記錄在sys.sysindexes這個系統表的rowmodctr欄位中,
  該表的統計資訊更新之後,該欄位清零,然後再次累積記錄表上的資料變化。

  

  這個資訊非常好使,為人工更新統計資訊提供了重要的依據,
  比如,對於1000W行的表,可以指定變化超過20W行(根據業務情況自定義)之後,手動更新統計資訊,
  對於5000W行的表,可以指定變化超過60W行(根據業務情況自定義)之後,手動更新統計資訊,
  同時根據不同的表,在相對較小的表上,指定相對較高的取樣百分比,在相對較大的表上,指定相對較低的取樣百分比
  比如對於1000W行的表,更新統計資訊的時候取樣百分比定位60%,對於5000W行的表,更新統計資訊的時候取樣百分比定位30%
  這樣,可以自行決定資料變化了多少之後更新統計資訊,以及動態地決定不同表的不同取樣百分比,達到一個合理的目的。
  當然,最後強調一下,我說的每一個數據都是相對的,而不是絕對的,都是僅做參考,
  具體還要你自己結合自己的伺服器軟硬體以環境及維護視窗時間去嘗試,一切沒有死的標準。

總結:統計資訊的準確性對執行計劃的生成有著至關重要的影響,本文粗略分析了統計資訊的跟新規律以及要更新統計資訊時候要注意的問題,
   在人為干預統計資訊更新的時候,需要根據具體的情況(表資料流量,伺服器軟硬體環境,維護視窗期等)在效率與準確性之間作出合理的選擇。