SQL Server調優系列進階篇(深刻剖析統計信息)

前言html

通過前幾篇的分析,其實大致已經初窺到SQL Server統計信息的重要性了,因此本篇就要祭出這個神器了。數據庫

該篇內容會很長,坐好板凳,瓜子零食之類...併發

不廢話,進正題post

技術準備性能

數據庫版本爲SQL Server2008R2,利用微軟的之前的案例庫(Northwind)進行分析,部份內容也會應用微軟的另外一個案例庫AdventureWorks學習

相信瞭解SQL Server的朋友,對這兩個庫都不會太陌生。優化

概念理解url

關於SQL Server中的統計信息,在聯機叢書中是這樣解釋的spa

查詢優化的統計信息是一些對象,這些對象包含與值在表或索引視圖的一列或多列中的分佈有關的統計信息。查詢優化器使用這些統計信息來估計查詢結果中的基數或行數。經過這些基數估計,查詢優化器能夠建立高質量的查詢計劃。例如,查詢優化器可使用基數估計選擇索引查找運算符而不是耗費更多資源的索引掃描運算符,從而提升查詢性能。3d

其實關於統計信息的做用通俗點將就是:SQL Server經過統計信息理解庫中每張表的數據內容項分佈,知道里面數據「長得啥德行,作到心中有數」,這樣每次查詢語句的時候就能夠根據表中的數據分佈,基本能定位到要查找數據的內容位置。

好比,我記得我之前有篇文章寫過一個相同的查詢語句,可是產生了徹底不一樣的查詢計劃,這裏回顧下,基本以下:

SELECT * FROM Person.Contact
WHERE FirstName LIKE 'K%'

SELECT * FROM Person.Contact
WHERE FirstName LIKE 'Y%'

徹底相同的查詢語句,只是查詢條件不一樣,一個查找以K開頭的顧客,一個查找以Y開頭的顧客,卻產生了徹底不一樣的查詢計劃。

其實,這裏的緣由就是統計信息在做祟。

咱們知道,在這張表的FirstName字段存在一個非彙集索引,目標就是爲了提高如上面的查詢語句的性能。

可是這張表裏面FirstName字段中的數據內容以K開頭的顧客存在1255行,也就是若是利用非彙集索引查找的方式,須要產生1225次IO操做,這可能不是最糟的,糟的還在後面,由於咱們獲取的數據字段並不所有在FirstName字段中,而須要額外的書籤查找來獲取,而這個書籤查找會產生的大量的隨機IO操做。記住:這裏是隨機IO。關於這裏的查找方式在咱們第一篇文章中就有介紹。

因此相比利用非彙集索引所帶來的消耗相比,所有的因此索引掃描來的更划算,由於它依次掃描就能夠獲取想要的數據。

而以Y開頭的就只有37行,37行數據徹底經過非彙集索引獲取,再加一部分的書籤查找很顯然是一個很划算的方式。由於它數據量少,產生的隨機IO量相對也會少。

因此,這裏的問題來了:

SQL Server是如何知道這張表裏FirstName字段中以K開頭的顧客會比較多,而以Y開頭反而少呢?。

這裏就是統計信息在做祟了,它不但知道FirstName字段中各行數據的內容「長啥樣」,而且仍是知道每行數據的分佈狀況。

其實,這就比如在圖書庫中,每一個書架就是一張表,而每本書就是一行數據,索引就好像圖書館書籍列表,好比按類區分,而統計信息就好像是每類書籍的多少以及存放書架位置。因此你借一本書的時候,須要藉助索引來查看,而後利用統計信息指導位置,這樣才能獲取書本。

但願這樣解釋,看官已經明白了統計信息的做用了。

 

這裏多談點,有不少童鞋沒有深刻了解索引和統計信息的做用前提下,在看過不少調優的文章以後,只深諳了一句話:調優嘛,建立索引就好了。

我不否定建立索引這種方式調優方式的做用性,可是不少時候關於建索引的技巧卻不瞭解。更巧的是大部分狀況下屬於誤打誤撞建立完索引後,性能果然提高了,而有時候建立的索引卻毫無用處,只會影響表的其它操做的性能(尤爲是Insert),更有甚者會產生死鎖狀況。

並且,關於索引項的做用,其實不少的狀況下,並不想你想象的那麼美好,後續文章咱們會分析那些索引失效的緣由。

因此遇到問題,其實還要經過表象理解其本質,這樣才能作到真正的有的放矢,有把握的解決問題。

 

解析統計信息

咱們來詳細分析一下統計信息中的內容項,咱們知道在上面的語句中,在表Customers中ContactName列中存在一個非彙集索引項,因此在該列存在統計信息,咱們能夠經過以下腳本查看該表的統計信息列表

sp_helpstats Customers

而後經過如下命令來查看該統計信息的詳細內容,代碼以下

DBCC SHOW_STATISTICS(Customers,ContactName)

每個統計信息的內容都包含以上三部分的內容。

咱們依次來分析下,經過這三部份內容SQL Server如何瞭解該列數據的內容分佈的。

a、統計信息的整體屬性項

該部分包含如下幾列:

  • Name:統計信息的名稱。
  • Updated:統計信息的最近一次更新時間,這個時間信息很重要,根據它咱們能知道該統計信息何時更新的,是否是最新的,是否是存在統計信息更新不及時形成統計的當前數據分佈不許確等問題。
  • Rows:描述當前表中的總行數。
  • Rows Sampled:統計信息的抽樣數據。當數據量比較多的時候,統計信息的獲取是採用的抽樣的方式統計的,若是數據量比較就會經過掃描所有獲取比較精確的統計值。好比,上面的例子中抽樣數據就爲91行。
  • Steps:步長值。也就是SQL Server統計信息的根據數據行的分組的個數。這個步長值也是有SQL Server本身肯定的,由於步長越小,描述的數據越詳細,可是消耗也越多,因此SQL Server會本身平衡這個值。
  • Density:密度值,也就是列值前綴的大小。
  • Average Key length:全部列的平均長度。
  • String Index:表示統計值是否爲字符串的統計信息。這裏字符串的評估目的是爲了支持LIKE關鍵字的搜索。
  • Filter Expression:過濾表達式,這個是SQL Server2008之後版本的新特性,支持添加過濾表達式,更加細粒度進行統計分析。
  • Unfiltered Rows:沒有通過表達式過濾的行,也是新特性。

通過上面部分的數據,統計信息已經分析出該列數據的最近更新時間、數據量、數據長度、數據類型等信息值。

 

b、統計信息的覆蓋索引項

All density:反映索引列的稠密度值。這是一個很是重要的值,SQL Server會根據這個評分項來決定該索引的有效程度。

該分值的計算公式爲:density=1/表中非重複的行數。因此該稠密度值取值範圍爲:0-1。

該值越小說明該列的索引項選擇性更強,也就說該索引更有效。理想的狀況是所有爲非重複值,也就是說都是惟一值,這樣它的數最小。

舉個例子:好比上面的例子該列存在91行,假如顧客不存在重名的狀況下,那麼該密度值就爲1/91=0.010989,該列爲性別列,那麼它只存在兩個值:男、女,那麼該列的密度值就爲0.5,因此相比而言SQL Server在索引選擇的時候很顯然就會選擇ContactName(顧客名字)列。

簡單點講:就是當前索引的選擇性高,它的稠密度值就小,那麼它就重複值少,這樣篩選的時候更容易找到結果值。相反,重複值多選擇性就差,好比性別,一次過濾只能過濾掉一半的記錄。

Average Length:索引的平均長度。

Columns:索引列的名稱。這裏由於咱們是非彙集索引,因此會存在兩行,一行爲ContactName索引列,一行爲ContactName索引列和彙集索引的列值CustomerID組合列。但願能明白這裏,索引基礎知識。

經過以上部分信息,SQL Server會知道該部分的數據獲取方式那個更快,更有效。

 

c、統計信息的直方圖信息

咱們接着分析第三部分,該列直方圖信息,經過這塊SQL Server能直觀「掌控」該列的數據分佈內容,咱們來看

  • RANGE_HI_KEY:直方圖中每一組數據的最大值。這個好理解,若是數據量大的話,通過分組,這個值就是當前組的最大值。上面例子的統計信息總共分了90組,總共才91行,也就是說,SQL Server爲了準確的描述該列的值,大部分每一個組只取了一個值,只有一個組取了倆值。
  • RANGE_ROWS:直方圖的沒組數據的區間行數(不包括最大值)。這裏咱們說了總共就91行,它分了90組,因此有一組會存在兩個值,咱們找到它:
  • EQ_ROWS:這裏表示和上面最大值相等的行數目。由於咱們不包含同樣的,因此這裏值都爲 1
  • DISTINCT_RANGE_ROWS:直方圖每組數據區間的非重複值的數目。上限值除外。
  • AVG_RANGE_ROWS:每一個直方圖平均的行數。

通過最後一部分的描述,SQL Server已經徹底掌控了該表中該字段的數據內容分佈了。想獲取那些數據根據它就能夠從容獲取到,而且統計信息是排序了的。

因此當咱們每次寫的T-SQL語句,它都能根據統計信息評估出要獲取的數據量多少,而且找到最合適的執行計劃來執行。

我也相信通過上面三部分的分析,關於文章開篇咱們提到的那個關於‘K’和‘Y’的問題會找到答案了,這裏不解釋了。

固然,若是數據量特別大,統計信息的維護也會有小小的失誤,而這時候就須要咱們來站出來及時的彌補。

 

建立統計信息

經過上面的介紹,其實咱們已經看到了統計信息的強大做用了,因此對於數據庫來講它的重要性就不言而喻了,所以,SQL Server會自動的建立統計信息,適時的更新統計信息,固然咱們能夠關閉掉,可是我很是不建議這麼作,緣由很簡單:No Do  No Die...

 

這兩項功能默認是開啓的,也就是說SQL Server會本身維護統計信息的準確性。

在平常維護中,咱們大可沒必要要去更改這兩項,固然也有比較極端的狀況,由於咱們知道更新統計信息也是一個消耗,在很是的大的併發的系統中須要關掉自動更新功能,這種狀況很是的少之又少,因此基本採用默認值就能夠。

在如下狀況下,SQL Server會自動的建立統計信息:

一、在索引建立時,SQL Server會自動的在索引列上建立統計信息。

二、當SQL Server想要使用某些列上的統計信息,發現沒有的時候,這時候會自動建立統計信息。

三、固然,咱們也能夠手動建立。

好比,自動建立的例子

select * into CustomersStats from Customers
sp_helpstats CustomersStats

來添加一個查詢語句,而後再查看統計信息

select * from CustomersStats
where ContactName='Hanna Moos'
go
sp_helpstats CustomersStats
go

固然,咱們也能夠根據本身的狀況來手動建立,建立腳本以下

USE [Northwind]
GO
CREATE STATISTICS [CoustomersOne] ON [dbo].[CustomersStats]([CompanyName])
GO

SQL Server也提供了GUI的圖像化操做窗口,方便操做

 

在如下狀況下,SQL Server會自動的更新統計信息:

 一、若是統計信息是定義在普通的表格上,那麼當發生如下任一種的變化後,統計信息就會被觸發更新動做。

  • 表格從沒有數據變成大於等於1條數據。
  • 對於數據量小於500行的表格,當統計信息的第一個字段數據累計變化大於500之後。
  • 對於數據量大於500行的表格,當統計信息的第一個字段數據累計變化大於500+(20%*表格總的數據量)之後。因此對於較大的表,只有1/5以上的數據發生變化後,SQL Server纔會從新計算統計信息。

二、臨時表上也能夠有統計信息。這也是不少狀況下采用臨時表優化的緣由之一。其維護策略基本和普通表格同樣,可是表變量不能建立統計信息。

固然,咱們也能夠手動的更新統計信息,更新腳本以下:

UPDATE STATISTICS Customers WITH FULLSCAN

 

 

文章寫的有點糙....但篇幅已經稍長了....先到此吧...後續我再補充一部分關於統計信息的內容。

關於調優內容太普遍,咱們放在之後的篇幅中介紹,有興趣的能夠提早關注。

 

參考文獻

  • 參照書籍《Microsoft SQL Server企業級平臺管理實踐》
  • 參照書籍《SQL.Server.2005.技術內幕》系列

有問題能夠留言或者私信,隨時恭候有興趣的童鞋加入SQL SERVER的深刻研究。共同窗習,一塊兒進步。

 

文章最後給出前面幾篇的鏈接,如下內容基本涵蓋咱們平常中所寫的查詢運算的分解,看來有必要整理一篇目錄了.....

SQL Server調優系列基礎篇

SQL Server調優系列基礎篇(經常使用運算符總結)

SQL Server調優系列基礎篇(聯合運算符總結)

SQL Server調優系列基礎篇(並行運算總結)

SQL Server調優系列基礎篇(並行運算總結篇二)

SQL Server調優系列基礎篇(索引運算總結)

SQL Server調優系列基礎篇(子查詢運算總結)

-----------------如下進階篇-------------------

SQL Server調優系列進階篇(查詢優化器的運行方式)

SQL Server調優系列進階篇(查詢語句運行幾個指標值監測)

 

若是您看了本篇博客,以爲對您有所收穫,請不要吝嗇您的「推薦」。

相關文章
相關標籤/搜索