以文本方式查看主題 - 昂捷論壇 (http://www.26035.net/bbs/index.asp) -- □-技術研討會 (http://www.26035.net/bbs/list.asp?boardid=36) ---- SQLServer索引碎片和解決方法 (http://www.26035.net/bbs/dispbbs.asp?boardid=36&id=9035) |
||
-- 作者:飛絮 -- 發(fā)布時間:2013/11/7 15:22:13 -- SQLServer索引碎片和解決方法 毫無疑問,給表添加索引是有好處的,你要做的大部分工作就是維護索引,在數(shù)據(jù)更改期間索引可能產(chǎn)生碎片,所以一些維護是必要的。碎片可能是你查詢產(chǎn)生性能問題的來源。 那么到底什么是索引碎片呢?索引碎片實際上有2種形式:外部碎片和內(nèi)部碎片。不管哪種碎片基本上都會影響索引內(nèi)頁的使用。這也許是因為頁的邏輯順序錯誤(即外部碎片)或每頁存儲的數(shù)據(jù)量少于數(shù)據(jù)頁的容量(內(nèi)部錯誤)。無論索引產(chǎn)生了哪種類型的碎片,你都會因為它而面臨查詢的性能問題。 外部碎片 當索引頁不在邏輯順序上時就會產(chǎn)生外部碎片。索引創(chuàng)建時,索引鍵按照邏輯順序放在一組索引頁上。當新數(shù)據(jù)插入索引時,新的鍵可能放在存在的鍵之間。為了讓新的鍵按照正確的順序插入,可能會創(chuàng)建新的索引頁來存儲需要移動的那些存在的鍵。這些新的索引頁通常物理上不會和那些被移動的鍵原來所在的頁相鄰。創(chuàng)建新頁的過程會引起索引頁偏離邏輯順序。 下面的例子將比實際的言論更加清晰的解釋這個概念。 假定在任何另外的數(shù)據(jù)插入你的表之前存在索引上的結(jié)構(gòu)如下 (注:下面圖片里應該是7和8,原文里是6和8): INSERT語句往索引里添加新的數(shù)據(jù),假定添加的是5。INSERT將引起新頁創(chuàng)建,為了給5在原來的頁上留出空間,7和8被移到了新頁上。這個創(chuàng)建將引起索引頁偏離邏輯順序。 在有特定搜索或者返回無序結(jié)果集的查詢的情況下,偏離順序的索引頁不會引起問題。對于返回有序結(jié)果集的查詢,搜索那些無序的索引頁需要進行額外的處理。有序結(jié)果集的例子如查詢返回4到10之間的記錄。為了返回7和8,查詢不得不進行額外的頁切換。雖然一個額外的頁切換在一個長時間運行里是無關緊要的,然而想象一下一個有好幾百頁偏離順序的非常大的表的情形。 內(nèi)部碎片 當索引頁沒有用到最大量時就產(chǎn)生了內(nèi)部碎片。雖然在一個有頻繁數(shù)據(jù)插入的應用程序里這也許有幫助,然而設置一個fill factor(填充因子)會在索引頁上留下空間,服務器內(nèi)部碎片會導致索引尺寸增加,從而在返回需要的數(shù)據(jù)時要執(zhí)行額外的讀操作。這些額外的讀操作會降低查詢的性能。 怎樣確定索引是否有碎片? SQLServer提供了一個數(shù)據(jù)庫命令――DBCC SHOWCONTIG――來確定一個指定的表或索引是否有碎片。 DBCC SHOWCONTIG 數(shù)據(jù)庫平臺命令,用來顯示指定的表的數(shù)據(jù)和索引的碎片信息。 DBCC SHOWCONTIG 權限默認授予 sysadmin固定服務器角色或 db_owner 和 db_ddladmin固定數(shù)據(jù)庫角色的成員以及表的所有者且不可轉(zhuǎn)讓。 語法(SQLServer2000) DBCC SHOWCONTIG [ ( { table_name | table_id| view_name | view_id } [ , index_name | index_id ] ) ] [ WITH { ALL_INDEXES | FAST [ , ALL_INDEXES ] | TABLERESULTS [ , { ALL_INDEXES } ] [ , { FAST | ALL_LEVELS } ] } ] 語法(SQLServer7.0) DBCC SHOWCONTIG [ ( table_id [,index_id ] ) ] 示例: 顯示數(shù)據(jù)庫里所有索引的碎片信息 SET NOCOUNT ON USE pubs DBCC SHOWCONTIG WITH ALL_INDEXES GO 顯示指定表的所有索引的碎片信息 SET NOCOUNT ONUSE pubs DBCC SHOWCONTIG (authors) WITH ALL_INDEXES GO 顯示指定索引的碎片信息 SET NOCOUNT ON USE pubs DBCC SHOWCONTIG (authors,aunmind) GO DBCC SHOWCONTIG (\'表名\') 結(jié)果集 DBCC SHOWCONTIG將返回掃描頁數(shù)、掃描擴展盤區(qū)數(shù)、遍歷索引或表的頁時,DBCC 語句從一個擴展盤區(qū)移動到其它擴展盤區(qū)的次數(shù)、每個擴展盤區(qū)的頁數(shù)、掃描密度(最佳值是指在一切都連續(xù)地鏈接的情況下,擴展盤區(qū)更改的理想數(shù)目)。 DBCC SHOWCONTIG 正在掃描 \'authors\' 表... 表: \'authors\'(1977058079); 索引 ID: 1,數(shù)據(jù)庫 ID: 5 已執(zhí)行 TABLE 級別的掃描。 - 掃描頁數(shù).....................................: 1 - 掃描擴展盤區(qū)數(shù)...............................: 1 - 擴展盤區(qū)開關數(shù)...............................: 0 - 每個擴展盤區(qū)上的平均頁數(shù).....................: 1.0 - 掃描密度[最佳值:實際值]....................: 100.00%[1:1] - 邏輯掃描碎片.................................: 0.00% - 擴展盤區(qū)掃描碎片.............................: 0.00% - 每頁上的平均可用字節(jié)數(shù).......................: 6010.0 - 平均頁密度(完整)...........................: 25.75% DBCC 執(zhí)行完畢。如果 DBCC 輸出了錯誤信息,請與系統(tǒng)管理員聯(lián)系。 掃描頁數(shù):如果你知道行的近似尺寸和表或索引里的行數(shù),那么你可以估計出索引里的頁數(shù)。看看掃描頁數(shù),如果明顯比你估計的頁數(shù)要高,說明存在內(nèi)部碎片。 掃描擴展盤區(qū)數(shù):用掃描頁數(shù)除以8,四舍五入到下一個最高值。該值應該和DBCC SHOWCONTIG返回的掃描擴展盤區(qū)數(shù)一致。如果DBCC SHOWCONTIG返回的數(shù)高,說明存在外部碎片。碎片的嚴重程度依賴于剛才顯示的值比估計值高多少。 擴展盤區(qū)開關數(shù):該數(shù)應該等于掃描擴展盤區(qū)數(shù)減1。高了則說明有外部碎片。 每個擴展盤區(qū)上的平均頁數(shù):該數(shù)是掃描頁數(shù)除以掃描擴展盤區(qū)數(shù),一般是8。小于8說明有外部碎片。 掃描密度[最佳值:實際值]:DBCC SHOWCONTIG返回最有用的一個百分比。這是擴展盤區(qū)的最佳值和實際值的比率。該百分比應該盡可能靠近100%。低了則說明有外部碎片。 邏輯掃描碎片:無序頁的百分比。該百分比應該在0%到10%之間,高了則說明有外部碎片。 擴展盤區(qū)掃描碎片:無序擴展盤區(qū)在掃描索引葉級頁中所占的百分比。該百分比應該是0%,高了則說明有外部碎片。 每頁上的平均可用字節(jié)數(shù):所掃描的頁上的平均可用字節(jié)數(shù)。越高說明有內(nèi)部碎片,不過在你用這個數(shù)字決定是否有內(nèi)部碎片之前,應該考慮fill factor(填充因子)。 平均頁密度(完整):每頁上的平均可用字節(jié)數(shù)的百分比的相反數(shù)。低的百分比說明有內(nèi)部碎片。 備注 DBCC SHOWCONTIG實際上僅對那些大表有用。小表顯示的結(jié)果根本不符合正常標準,因為他們也許沒有由多于8個的頁面組成。你在查看小表上執(zhí)行DBCC SHOWCONTIG的結(jié)果時應該忽略一些結(jié)果。在處理小表時只需關心擴展盤區(qū)開關數(shù)、邏輯掃描碎片、每頁上的平均可用字節(jié)數(shù)、平均頁密度(完整)。 DBCC SHOWCONTIG默認輸出的結(jié)果是:掃描頁數(shù)、掃描擴展盤區(qū)數(shù)、擴展盤區(qū)開關數(shù)、每個擴展盤區(qū)上的平均頁數(shù)、掃描密度[最佳值:實際值]、邏輯掃描碎片、擴展盤區(qū)掃描碎片、每頁上的平均可用字節(jié)數(shù)、平均頁密度(完整)?梢杂肍AST和TABLERESULTS選項來控制這個輸出結(jié)果。 FAST選項指定執(zhí)行索引的快速掃描,輸出結(jié)果是最小的,該選項不讀索引的葉或數(shù)據(jù)頁且只返回掃描頁數(shù)、掃描擴展盤區(qū)數(shù)、掃描密度[最佳值:實際值]、邏輯掃描碎片。 TABLERESULTS選項將用行集的形式顯示信息,將返回擴展盤區(qū)開關數(shù)、掃描密度[最佳值:實際值]、邏輯掃描碎片、擴展盤區(qū)掃描碎片、每頁上的平均可用字節(jié)數(shù)、平均頁密度(完整)。 如果既指定FAST選項又指定TABLERESULTS選項,那么將返回對象名、對象ID、索引名、索引ID,頁數(shù)、擴展盤區(qū)開關數(shù)、掃描密度[最佳值:實際值]和邏輯掃描碎片。 ALL_INDEXES選項將顯示指定表和試圖的所有索引的結(jié)果,即使指定了一個索引。 ALL_LEVELS選項指定是否為所處理的每個索引的每個級別產(chǎn)生輸出(默認只輸出索引的頁級或表數(shù)據(jù)級的結(jié)果),并且只能與 TABLERESULTS 選項一起使用。 解決碎片問題 一旦你確定表或索引有碎片問題,那么你有4個選擇去解決那些問題: 刪除并重建索引 使用DROP_EXISTING子句重建索引 執(zhí)行DBCC DBREINDEX 執(zhí)行DBCC INDEXDEFRAG 盡管每一個技術都能達到你整理索引碎片的最終目的,但各有各的優(yōu)缺點。 刪除并重建索引 用DROP INDEX和CREATE INDEX或ALTER TABLE來刪除并重建索引有些缺陷包括在刪除重建期間索引會消失。在索引刪除重建時,對于查詢它不在可用,查詢性能也許會受到明顯的影響,直到重建索引為止。另一個潛在的缺陷是當都請求索引的時候會引起阻塞,直到重建索引為止。通過其他的處理也能解決阻塞,就是索引被使用的時候不刪除索引。另一個主要的缺陷是在用DROP INDEX和CREATE INDEX重建聚集索引時會引起非聚集索引重建兩次。刪除聚集索引時非聚集索引的行指針會指向數(shù)據(jù)堆,聚集索引重建時非聚集索引的行指針又會指回聚集索引的行位置。 刪除并重建索引的確有一個好處就是通過重新排序索引頁,使索引頁緊湊并刪除不需要的索引頁來完全重建索引。你也許需要考慮那些內(nèi)部和外部碎片都很高的情況下才使用,以使那些索引回到它們應該在的位置。 使用DROP_EXISTING子句重建索引 為了避免在重建聚集索引時表上的非聚集索引重建兩次,可以使用帶DROP_EXISTING子句的CREATE INDEX語句。這個子句會保留聚集索引鍵值,以避免非聚集索引重建兩次。和刪除并重建索引一樣,該方法也可能會引起阻塞和索引消失的問題。該方法的另一個缺陷是也強迫你去分別發(fā)現(xiàn)和修復表上的每一個索引。 除了和上一個方法一樣的好處之外,該方法的好處是不必重建非聚集索引兩次。這樣可以對那些帶約束的索引提供正確的索引定義以符合約束的要求。 執(zhí)行DBCC DBREINDEX DBCC DBREINDEX類似于第二種方法,但它物理地重建索引,允許SQLServer給索引分配新頁來減少內(nèi)部和外部碎片。DBCC DBREINDEX也能動態(tài)的重建帶約束的索引,不象第二種方法。 DBCC DBREINDEX的缺陷是會遇到或引起阻塞問題。DBCC DBREINDEX是作為一個事務來運行的,所以如果在完成之前中斷了,那么你會丟失所有已經(jīng)執(zhí)行過的碎片。 執(zhí)行DBCC INDEXDEFRAG DBCC INDEXDEFRAG(在SQLServer2000中可用)按照索引鍵的邏輯順序,通過重新整理索引里存在的葉頁來減少外部碎片,通過壓縮索引頁里的行然后刪除那些由此產(chǎn)生的不需要的頁來減少內(nèi)部碎片。它不會遇到阻塞問題但它的結(jié)果沒有其他幾個方法徹底。這是因為DBCC INDEXDEFRAG跳過了鎖定的頁且不使用任何新頁來重新排序索引。如果索引的碎片數(shù)量大的話你也許會發(fā)現(xiàn)DBCC INDEXDEFRAG比重建索引花費的時間更長。DBCC INDEXDEFRAG比其他方法的確有好處的是在其他過程訪問索引時也能進行碎片整理,不會引起其他方法的阻塞問題。 |