基礎(chǔ)知識(shí)普及:
對于篩選索引,MSDN如是說:
篩選索引是一種經(jīng)過優(yōu)化的非聚集索引,尤其適用于涵蓋從定義完善的數(shù)據(jù)子集中選擇數(shù)據(jù)的查詢。 篩選索引使用篩選謂詞對表中的部分行進(jìn)行索引。 與全表索引相比,設(shè)計(jì)良好的篩選索引可以提高查詢性能、減少索引維護(hù)開銷并可降低索引存儲(chǔ)開銷。
篩選索引與全表索引相比具有以下優(yōu)點(diǎn):
提高了查詢性能和計(jì)劃質(zhì)量 設(shè)計(jì)良好的篩選索引可以提高查詢性能和執(zhí)行計(jì)劃質(zhì)量,因?yàn)樗热矸蔷奂饕〔⑶揖哂薪?jīng)過篩選的統(tǒng)計(jì)信息。 與全表統(tǒng)計(jì)信息相比,經(jīng)過篩選的統(tǒng)計(jì)信息更加準(zhǔn)確,因?yàn)樗鼈冎缓w篩選索引中的行。
減少了索引維護(hù)開銷 僅在數(shù)據(jù)操作語言 (DML) 語句對索引中的數(shù)據(jù)產(chǎn)生影響時(shí),才對索引進(jìn)行維護(hù)。 與全表非聚集索引相比,篩選索引減少了索引維護(hù)開銷,因?yàn)樗〔⑶覂H在索引中的數(shù)據(jù)更改時(shí)才進(jìn)行維護(hù)。 篩選索引的數(shù)量可以非常多,特別是在其中包含很少更改的數(shù)據(jù)時(shí)。 同樣,如果篩選索引只包含頻繁修改的數(shù)據(jù),則索引大小較小時(shí)可以減少更新統(tǒng)計(jì)信息的開銷。
減少了索引存儲(chǔ)開銷 在沒必要?jiǎng)?chuàng)建全表索引時(shí),創(chuàng)建篩選索引可以減少非聚集索引的磁盤存儲(chǔ)開銷。 可以使用多個(gè)篩選索引替換一個(gè)全表非聚集索引而不會(huì)明顯增加存儲(chǔ)需求。
MSDN地址:http://msdn.microsoft.com/zh-cn/library/cc280372(v=sql.105).aspx
--========================================================
基礎(chǔ)案例介紹:
在很多場景中,過濾索引能解決很多復(fù)合索引無法處理的問題,成為一些特殊問題的必殺技,如下面的查詢:
SELECT TOP(10) C2FROM TB1WHERE C1>5ORDER BY C2 DESC
如果按C2倒序排序后,排在結(jié)果集前面的大多數(shù)行都滿足C1>5的條件的話,那么我們可以建立以下索引來優(yōu)化:
CREATE INDEX IDX_C2_INCON TB1(C2)INCLUDE(C1)
但如果滿足C1>5的行特別少或者排在結(jié)果集尾部的話,那么查詢需要遍歷索引的大部分才能找到匹配的數(shù)據(jù)返回給客戶,從而導(dǎo)致大量邏輯IO開銷。
如果滿足C1>5的行比較少,那么可以使用以下索引來優(yōu)化:
CREATE INDEX IDX_C1_C2ON TB1(C1,C2)
雖然以上索引能幫助快速找到所有C1<5的行,但仍需要經(jīng)過一次排序后才能獲得TOP(5)的數(shù)據(jù),而排序又會(huì)導(dǎo)致CPU資源開銷。
隨著SQL SERVER 2008引入過濾索引后,這樣的查詢便可以輕松搞定,我們只需要建立以下索引:
CREATE INDEX IDX_C2_WHON TB1(C2)WHERE C1>5
查詢可以通過索引很快找到滿足C1>5并且按C2排序的TOP 5的數(shù)據(jù),最小化地消耗CPU和IO資源。--===========================================================
在SQL Server中,數(shù)據(jù)庫選擇的“自動(dòng)創(chuàng)建統(tǒng)計(jì)(Auto Create Statistics)”選項(xiàng)默認(rèn)為開啟狀態(tài), 隨著索引的創(chuàng)建,數(shù)據(jù)庫會(huì)自動(dòng)創(chuàng)建與之對應(yīng)的統(tǒng)計(jì)信息,創(chuàng)建過濾索引的過程同樣會(huì)創(chuàng)建對于的統(tǒng)計(jì)信息。
當(dāng)數(shù)據(jù)庫設(shè)置為自動(dòng)更新統(tǒng)計(jì)時(shí)(數(shù)據(jù)庫未開啟跟蹤標(biāo)志情況下),SQL Server 監(jiān)控表中的數(shù)據(jù)更改,當(dāng)更改滿足一下條件之一時(shí)更新:1.向空表插入數(shù)據(jù)時(shí) 2.少于500行的表增加500行或者更多 3.當(dāng)表中行多于500行時(shí),數(shù)據(jù)的變化量大于20%時(shí) (在SQL SERVER 2000中,指的是20%的行被修改,而在SQL SERVER 2005/2008中,指的是20%的列數(shù)據(jù)被修改)
PS: 20%不是一個(gè)絕對值
--===========================================================
那么問題出來了,這個(gè)20%比例對過濾索引的統(tǒng)計(jì)信息是否滿足呢?如果滿足的話,哪基數(shù)是什么呢?是表中的數(shù)據(jù)還是當(dāng)前滿足條件的數(shù)據(jù)呢?
讓我們來做個(gè)測試吧
首先準(zhǔn)備測試數(shù)據(jù)
--創(chuàng)建表,并插入5000行數(shù)據(jù)SELECT TOP(5000) IDENTITY(INT,1,1) AS ID,* INTO TB001FROM SYS.all_columnsGO--創(chuàng)建聚簇索引CREATE CLUSTERED INDEX IDX_IDON TB001(ID)GO--創(chuàng)建過濾索引CREATE INDEX IDX_COLUMNIDON TB001(object_id)WHERE Column_id<3GO--再導(dǎo)入25000行數(shù)據(jù)INSERT INTO TB001SELECT TOP(5000) * FROM SYS.all_columnsGO 5--更新統(tǒng)計(jì)信息UPDATE STATISTICS TB001GO
查看過濾索引的統(tǒng)計(jì)信息
--查看過濾索引的統(tǒng)計(jì)信息DBCC SHOW_STATISTICS('dbo.TB001','IDX_COLUMNID')GO
目前表中有30000行數(shù)據(jù),滿足條件的數(shù)據(jù)是5412行,都超過500行的限制,考慮20%這是一個(gè)參考值而不是絕對值,我們測試值調(diào)整到50%;為了避免版本問題導(dǎo)致更新行還是更新列的問題,我們統(tǒng)一使用插入方式來測試。
1.首先測試插入5412*50%=2706行數(shù)據(jù)
--再導(dǎo)入2706行數(shù)據(jù)INSERT INTO TB001SELECT TOP(2706) * FROM SYS.all_columnsGO--執(zhí)行查詢嘗試觸發(fā)統(tǒng)計(jì)更新SELECT TOP(1) object_id,COUNT(1)FROM TB001WHERE Column_id<3GROUP BY object_idORDER BY COUNT(1) DESC--查看過濾索引的統(tǒng)計(jì)信息DBCC SHOW_STATISTICS('dbo.TB001','IDX_COLUMNID')GO
統(tǒng)計(jì)信息未發(fā)生變化,仍舊是:
2.首先測試插入30000*50%=15000行數(shù)據(jù)(需要考慮之前已插入的2706條數(shù)據(jù))
--再導(dǎo)入25000行數(shù)據(jù)INSERT INTO TB001SELECT TOP(5000) * FROM SYS.all_columnsGOINSERT INTO TB001SELECT TOP(5000) * FROM SYS.all_columnsGO--由于之前插入2706條數(shù)據(jù),因此第三次插入2294INSERT INTO TB001SELECT TOP(2294) * FROM SYS.all_columnsGOSELECT COUNT(1) FROM TB001--執(zhí)行查詢嘗試觸發(fā)統(tǒng)計(jì)更新SELECT TOP(1) object_id,COUNT(1)FROM TB001WHERE Column_id<3GROUP BY object_idORDER BY COUNT(1) DESCGO--查看過濾索引的統(tǒng)計(jì)信息DBCC SHOW_STATISTICS('dbo.TB001','IDX_COLUMNID')GO
感謝上蒼,感謝黨,統(tǒng)計(jì)更新了,世界和平了,媽媽再也不用擔(dān)心我的成績了(畢業(yè)很多年啦,淚流滿面啊)!!!
--=====================================================
在測試過程中,最開始想使用以下查詢來觸發(fā):
SELECT TOP(1) object_idFROM TB001WHERE Column_id<3AND Column_id=82873218ORDER BY object_idGOSELECT COUNT(1) FROM TB001WHERE Column_id<3GO
結(jié)果得出一個(gè)錯(cuò)誤結(jié)論,經(jīng)多次測試后才發(fā)現(xiàn)上述兩個(gè)查詢雖然使用到索引,但是無法觸發(fā)統(tǒng)計(jì)更新。
--=====================================================
總結(jié):無論是復(fù)合索引還是過濾索引的統(tǒng)計(jì)信息,都是以上一次統(tǒng)計(jì)信息更新時(shí)表的行數(shù)作為基數(shù),當(dāng)更新達(dá)到按20%左右的比例左右后,由查詢執(zhí)行來觸發(fā)統(tǒng)計(jì)自動(dòng)更新。
PS1: 更新數(shù)指的是操作影響的行數(shù),如執(zhí)行10次UPDATE操作,每次UPDATE影響50行數(shù)據(jù),那么更新數(shù)為500,即使這10次UPDATE沒有改變?nèi)魏我粭l數(shù)據(jù)(類似UPDATE T1 SET C1=C1這類操作)
PS2: 即使更新數(shù)達(dá)到20%左右,查詢使用到該過濾索引,也不一定會(huì)觸發(fā)統(tǒng)計(jì)更新,只有查詢優(yōu)化器認(rèn)為該統(tǒng)計(jì)過期并且需要一個(gè)更新過的統(tǒng)計(jì)信息來生成執(zhí)行計(jì)劃時(shí),才會(huì)觸發(fā)統(tǒng)計(jì)自動(dòng)更新
PS2:由于過濾索引的只存放滿足過濾條件的數(shù)據(jù)的特殊性,存在一些場景下,索引數(shù)據(jù)變化很多而對應(yīng)的統(tǒng)計(jì)信息尚未滿足過期(無效)條件,從而導(dǎo)致生成不高效的執(zhí)行計(jì)劃,因此有很多高手大神都建議專門針對這些有過濾條件的統(tǒng)計(jì)信息制定更新計(jì)劃,提高其更新頻率
PS3:除創(chuàng)建過濾索引會(huì)生成有過濾條件的統(tǒng)計(jì)信息外,數(shù)據(jù)庫管理員也可以主動(dòng)添加有過濾條件的統(tǒng)計(jì)信息,供執(zhí)行優(yōu)化器使用。
--=============================================
漂亮妹子看多了,來點(diǎn)普通的,哈哈
新聞熱點(diǎn)
疑難解答
圖片精選