统计--过滤(筛选)索引的统计信息过期问题测试
基礎知識普及:
對于篩選索引,MSDN如是說:
篩選索引是一種經過優化的非聚集索引,尤其適用于涵蓋從定義完善的數據子集中選擇數據的查詢。 篩選索引使用篩選謂詞對表中的部分行進行索引。 與全表索引相比,設計良好的篩選索引可以提高查詢性能、減少索引維護開銷并可降低索引存儲開銷。
篩選索引與全表索引相比具有以下優點:
提高了查詢性能和計劃質量 設計良好的篩選索引可以提高查詢性能和執行計劃質量,因為它比全表非聚集索引小并且具有經過篩選的統計信息。? 與全表統計信息相比,經過篩選的統計信息更加準確,因為它們只涵蓋篩選索引中的行。
減少了索引維護開銷 僅在數據操作語言 (DML) 語句對索引中的數據產生影響時,才對索引進行維護。? 與全表非聚集索引相比,篩選索引減少了索引維護開銷,因為它更小并且僅在索引中的數據更改時才進行維護。 篩選索引的數量可以非常多,特別是在其中包含很少更改的數據時。 同樣,如果篩選索引只包含頻繁修改的數據,則索引大小較小時可以減少更新統計信息的開銷。
減少了索引存儲開銷 在沒必要創建全表索引時,創建篩選索引可以減少非聚集索引的磁盤存儲開銷。? 可以使用多個篩選索引替換一個全表非聚集索引而不會明顯增加存儲需求。
MSDN地址:http://msdn.microsoft.com/zh-cn/library/cc280372(v=sql.105).aspx
?--========================================================
基礎案例介紹:
在很多場景中,過濾索引能解決很多復合索引無法處理的問題,成為一些特殊問題的必殺技,如下面的查詢:
SELECT TOP(10) C2 FROM TB1 WHERE C1>5 ORDER BY C2 DESC如果按C2倒序排序后,排在結果集前面的大多數行都滿足C1>5的條件的話,那么我們可以建立以下索引來優化:
CREATE INDEX IDX_C2_INC ON TB1(C2) INCLUDE(C1)但如果滿足C1>5的行特別少或者排在結果集尾部的話,那么查詢需要遍歷索引的大部分才能找到匹配的數據返回給客戶,從而導致大量邏輯IO開銷。
如果滿足C1>5的行比較少,那么可以使用以下索引來優化:
CREATE INDEX IDX_C1_C2 ON TB1(C1,C2)雖然以上索引能幫助快速找到所有C1<5的行,但仍需要經過一次排序后才能獲得TOP(5)的數據,而排序又會導致CPU資源開銷。
隨著SQL SERVER 2008引入過濾索引后,這樣的查詢便可以輕松搞定,我們只需要建立以下索引:
CREATE INDEX IDX_C2_WH ON TB1(C2) WHERE C1>5查詢可以通過索引很快找到滿足C1>5并且按C2排序的TOP 5的數據,最小化地消耗CPU和IO資源。
--===========================================================
在SQL Server中,數據庫選擇的“自動創建統計(Auto Create Statistics)”選項默認為開啟狀態, 隨著索引的創建,數據庫會自動創建與之對應的統計信息,創建過濾索引的過程同樣會創建對于的統計信息。
當數據庫設置為自動更新統計時(數據庫未開啟跟蹤標志情況下),SQL Server 監控表中的數據更改,當更改滿足一下條件之一時更新:
1.向空表插入數據時 
2.少于500行的表增加500行或者更多 
3.當表中行多于500行時,數據的變化量大于20%時 
(在SQL SERVER 2000中,指的是20%的行被修改,而在SQL SERVER 2005/2008中,指的是20%的列數據被修改)
PS: 20%不是一個絕對值
--===========================================================
那么問題出來了,這個20%比例對過濾索引的統計信息是否滿足呢?如果滿足的話,哪基數是什么呢?是表中的數據還是當前滿足條件的數據呢?
讓我們來做個測試吧
首先準備測試數據
--創建表,并插入5000行數據 SELECT TOP(5000) IDENTITY(INT,1,1) AS ID, * INTO TB001 FROM SYS.all_columns GO --創建聚簇索引 CREATE CLUSTERED INDEX IDX_ID ON TB001(ID) GO --創建過濾索引 CREATE INDEX IDX_COLUMNID ON TB001(object_id) WHERE Column_id<3 GO --再導入25000行數據 INSERT INTO TB001 SELECT TOP(5000) * FROM SYS.all_columns GO 5 --更新統計信息 UPDATE STATISTICS TB001 GO查看過濾索引的統計信息
--查看過濾索引的統計信息 DBCC SHOW_STATISTICS('dbo.TB001','IDX_COLUMNID') GO目前表中有30000行數據,滿足條件的數據是5412行,都超過500行的限制,考慮20%這是一個參考值而不是絕對值,我們測試值調整到50%;為了避免版本問題導致更新行還是更新列的問題,我們統一使用插入方式來測試。
1.首先測試插入5412*50%=2706行數據
--再導入2706行數據 INSERT INTO TB001 SELECT TOP(2706) * FROM SYS.all_columns GO --執行查詢嘗試觸發統計更新 SELECT TOP(1) object_id,COUNT(1)FROM TB001
WHERE Column_id<3
GROUP BY object_id
ORDER BY COUNT(1) DESC --查看過濾索引的統計信息 DBCC SHOW_STATISTICS('dbo.TB001','IDX_COLUMNID') GO
統計信息未發生變化,仍舊是:
2.首先測試插入30000*50%=15000行數據(需要考慮之前已插入的2706條數據)
--再導入25000行數據 INSERT INTO TB001 SELECT TOP(5000) * FROM SYS.all_columns GO INSERT INTO TB001 SELECT TOP(5000) * FROM SYS.all_columns GO --由于之前插入2706條數據,因此第三次插入2294 INSERT INTO TB001 SELECT TOP(2294) * FROM SYS.all_columns GO SELECT COUNT(1) FROM TB001--執行查詢嘗試觸發統計更新 SELECT TOP(1) object_id,COUNT(1)FROM TB001
WHERE Column_id<3
GROUP BY object_id
ORDER BY COUNT(1) DESC GO --查看過濾索引的統計信息 DBCC SHOW_STATISTICS('dbo.TB001','IDX_COLUMNID') GO
感謝上蒼,感謝黨,統計更新了,世界和平了,媽媽再也不用擔心我的成績了(畢業很多年啦,淚流滿面啊)!!!
--=====================================================
在測試過程中,最開始想使用以下查詢來觸發:
SELECT TOP(1) object_id FROM TB001 WHERE Column_id<3 AND Column_id=82873218 ORDER BY object_id GO SELECT COUNT(1) FROM TB001 WHERE Column_id<3 GO結果得出一個錯誤結論,經多次測試后才發現上述兩個查詢雖然使用到索引,但是無法觸發統計更新。
--=====================================================
總結:無論是復合索引還是過濾索引的統計信息,都是以上一次統計信息更新時表的行數作為基數,當更新達到按20%左右的比例左右后,由查詢執行來觸發統計自動更新。
PS1: 更新數指的是操作影響的行數,如執行10次UPDATE操作,每次UPDATE影響50行數據,那么更新數為500,即使這10次UPDATE沒有改變任何一條數據(類似UPDATE T1 SET C1=C1這類操作)
PS2: 即使更新數達到20%左右,查詢使用到該過濾索引,也不一定會觸發統計更新,只有查詢優化器認為該統計過期并且需要一個更新過的統計信息來生成執行計劃時,才會觸發統計自動更新
PS2:由于過濾索引的只存放滿足過濾條件的數據的特殊性,存在一些場景下,索引數據變化很多而對應的統計信息尚未滿足過期(無效)條件,從而導致生成不高效的執行計劃,因此有很多高手大神都建議專門針對這些有過濾條件的統計信息制定更新計劃,提高其更新頻率
PS3:除創建過濾索引會生成有過濾條件的統計信息外,數據庫管理員也可以主動添加有過濾條件的統計信息,供執行優化器使用。
--=============================================
漂亮妹子看多了,來點普通的,哈哈
?
轉載于:https://www.cnblogs.com/TeyGao/p/4050972.html
總結
以上是生活随笔為你收集整理的统计--过滤(筛选)索引的统计信息过期问题测试的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 【IOS】Target membersh
- 下一篇: CUDA编程入门极简教程
