SQL Server設定過濾條件提高索引效率
原創【51CTO獨家特稿】低碳指數:在這里為了方便計算和直觀,我們以Intel至強X7500處理器的TDP為標準計算能耗(TDP=130W/h=2.167W/m=0.036W/s)。另外根據中國林業局的數據,一棵樹一天吸收二氧化碳量為5.023kg,每一度電產生0.785公斤二氧化碳。
如果按照本文方法優化后數據庫執行時間由27秒縮減到14秒,也就是單位時間少47.8%的能量消耗。那么在一天里將減少1.486kw電能消耗,約合1.167kg二氧化碳排放,按我們的計算是一天減少0.232棵樹二氧化碳吸收量。
51CTO數據庫頻道向您推薦《數據庫性能優化與調試》和《SQL Server 2008/2005全解》專題,以便于您更好的理解本文。
設定過濾條件提高索引效率
優秀的索引是SQL Server數據庫性能的關鍵,然而高效的索引都是經過精心設計而成的。眾所周知,主鍵是儲存數據對象的***標識,如果數據表中沒有聚簇索引,為了維護主鍵的***性,SQL Server數據庫在默認情況下將為主鍵創建聚簇索引(Clustered index),除非用戶特別指定將索引創建為非聚簇索引(Non-clustered index)。
毫無疑問,我們應當為頻繁訪問的數據創建聚簇索引,當然頻繁訪問的字段應當經過詳細的分析和慎重選擇,并且索引值應當盡可能短。提到創建索引,大家往往首先想到主鍵,但是主鍵的數據并不一定被頻繁訪問,而且很多時候為了保證主鍵的***性,主鍵的數值往往不是很短,比如我們經常會選擇全局***標識符(GUID)類型作為主鍵的數據類型,***標識符的長度一般是16個字節,就長度而言,這種數據類型并不是最理想的聚簇索引選項,在這種情況下,可以為主鍵創建非聚簇索引,因為主鍵值在WHERE語句中用來查詢特定的記錄是非常高效的,創建非聚簇索引可以將查詢的效率再上一個臺階。如果您選擇了整型作為主鍵的數據類型,那就可以考慮將為主鍵生成聚簇索引。
SQL Server 2008為我們提供了另外一種索引——設定過濾條件索引(Filtered index),一個設定過濾條件索引是一個特殊的非聚簇索引,它是某些字段的特定子集。換句話說,設定過濾條件索引是基于一部分選定的字段生成的。比如說,在銷售業績數據表中,分公司所在城市的數據存儲在City字段,如果我們創建一個非聚簇索引,那么所有的分公司所在的城市,都會被納入索引當中。但是如果我們使用設定過濾條件索引,我們就可以只選擇一部分城市被索引,比如北京,上海和廣州,代碼如下:
- CREATE NONCLUSTERED INDEX FilteredCities ON Sales(City)
- WHERE City IN ('北京','上海','廣州')
與常規索引的區別在于,我們使用了WHERE語句來設定我們的過濾條件。假定公司的絕大部分收入都是來自于這三個城市的,那么我們的數據庫查詢會經常訪問到在這三個城市產生的銷售記錄,在這種情況下,設定過濾條件索引會占據較少的磁盤空間,因為只有City字段的數值是北京,上海和廣州的記錄會被索引,這些記錄只是整個銷售數據表格中的一部分。
利用設定過濾條件索引可以提升數據庫的性能,首先,只有被索引到記錄發生變化的時候,才需要重建索引。比如,某一條在北京發生的銷售記錄需要調整,在更新操作之后,索引也要隨之更新,這跟其他的索引是一樣的。但如果發生在西安的銷售記錄發生了變化,無論添加或刪除了多少條記錄,我們之前建立的設定過濾條件索引都是不需要任何操作的,因為只有位于北京、上海和廣州分公司的銷售記錄有影響到這個索引。設定過濾條件索引的另外一個優勢是可以減少磁盤讀寫操作,比如我們要查詢所有北京分公司的銷售記錄,那么使用剛才建立的設定過濾條件索引比常規的非聚簇索引要減少很多不必要的磁盤操作。
為了驗證設定過濾條件索引所帶來的性能優勢,我們進行了對比測試。
首先,我們在VirtualBox虛擬機里安裝Windows Server 2008 R2與SQL Server 2008 R2中文版,順便說一下,我們安裝的都是可以試用180天的試用版,在微軟官方網站可以直接下載,而且現在試用版也不需要申請序列號了,在安裝過程中可以直接選擇安裝180天試用,就可以直接安裝,這位實驗和學習帶來了不少便利。
我們在數據庫中創建了一個500萬條記錄的銷售數據表,當然,銷售金額都是隨機產生的,而city字段,我們隨機產生1到9這9個不同的數字,然后再根據需要將它們在替換為不同的城市,在這個實驗中,我們把北京、上海和廣州的銷售記錄總比例設定為67%。
點擊查看清晰大圖
接下來,我們將虛擬機進行完整的復制,這樣就可以得到兩套完全一致的操作系統和數據庫,數據庫中已經包含了我們剛剛創建的數據表,相關過程可以參考VirtualBox的技術文檔。復制整個虛擬機的目的在于確保硬件和操作系統對數據庫性能的影響最小,以便于我們將注意力集中在不同索引方式下,數據庫性能的表現。
下一步,我們在***個虛擬機中創建city字段的完整的非聚簇索引,代碼如下:
- CREATE NONCLUSTERED INDEX FilteredCities ON Sales(City)
在第二個虛擬機中,我們創建設定過濾條件索引,代碼如下
- CREATE NONCLUSTERED INDEX FilteredCities ON Sales(City)
- WHERE City IN ('北京','上海','廣州')
點擊查看清晰大圖
然后我們在兩個虛擬機的數據庫中來計算北京、上海和廣州這三個城市的銷售金額總和,代碼如下
- SELECT SUM(Value) FROM Sales
- WHERE City = '北京' or City = '上海' or City = '廣州'
在使用完整的非聚簇索引的情況下,我們花費了27秒,而使用設定過濾條件索引的情況下,我們只需要14秒就得到了計算結果,可見非聚簇索引在大規模數據計算的情況下,對性能的提升還是非常可觀的,我們截取的屏幕如下,供大家參考:
優化前:點擊查看清晰大圖
優化后:點擊查看清晰大圖
在選擇過濾條件的時候,我們需要考慮哪些數據會隨著時間的推移而經常變化,比如,新增加的記錄是添加到索引的中間還是末尾?當記錄刪除的時候,索引值是否需要隨之刪除?這些問題的答案都會影響我們對索引的設計。
在這里,我們需要用到填充因子(Fill Factor),填充因子是一個以百分比表示的數值,在重建索引的時候,填充因子的值決定了每個頁面上要填充數據的空間百分比,以便保留一些剩余空間作為以后擴展索引的可用空間,以下代碼演示了如何將填充因子設定為80,只有在高級選項打開的情況下才能設定填充因子:
- Use DatabseName;
- GO
- sp_configure 'show advanced options', 1;
- GO
- RECONFIGURE;
- GO
- sp_configure 'fill factor', 80;
- GO
如果填充因子的值是100,那么索引頁就被會全部填充。我們一般考慮將填充因子設定為50到80中間的數值來保證添加新值的時候,不會發生頁拆分。如果經常需要在索引末尾添加字段值的話,可以考慮將填充因子設定為90到100之間的值。最理想的狀態是同時保證最少次數的的頁拆分和索引重建。
【編輯推薦】