1. 程式人生 > >通過DBCC整理Sqlserver數據庫表索引碎片

通過DBCC整理Sqlserver數據庫表索引碎片

ext log cto 說明 切換 sdn remove microsoft 索引

    昨天檢查了一張效率極慢的表,兩年多沒有維護,邏輯掃描碎片高達99.81%,於是開始對這個表進行重點跟蹤和記錄日誌。今天用DBCC SHOWCONTIG WITH TABLERESULTS  命令檢查了一下所有表的概況,然後參照著MSDN對字段的說明,發現問題比較嚴重。ScanDensity(這是“最佳計數”與“實際計數”的比率。如果所有內容都是連續的,則該值為 100;如果該值小於 100,則存在一些碎片)有的甚至在16.6666666666667,其他掃描密度等指標也特別不理想。

    檢查:

    隨便貼出一個表的掃描結果:
    --------------------------------------------------------------------------------------------------------------------------

    DBCC SHOWCONTIG 正在掃描 
UserInfo 表... 表: UserInfo (1646628909);索引 ID: 1,數據庫 ID: 7 已執行 TABLE 級別的掃描。 - 掃描頁數................................: 367 - 掃描區數..............................: 48 - 區切換次數..............................: 355 - 每個區的平均頁數........................: 7.6 - 掃描密度 [最佳計數:實際計數].......: 12.92
% [46:356] - 邏輯掃描碎片 ..................: 95.37% - 區掃描碎片 ..................: 47.92% - 每頁的平均可用字節數.....................: 2996.8 - 平均頁密度(滿).....................: 62.98% DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系。 -------------------------------------------------------------------------------------------------------------------------- 解釋如下( 查看解釋來源點此 ,MSDN解釋太官方,還是用簡單點的話來解釋): 掃描頁數:如果你知道行的近似尺寸和表或索引裏的行數,那麽你可以估計出索引裏的頁數。看看掃描頁數,如果明顯比你估計的頁數要高,說明存在內部碎片。 掃描擴展盤區數:用掃描頁數除以8,四舍五入到下一個最高值。該值應該和DBCC SHOWCONTIG返回的掃描擴展盤區數一致。如果DBCC SHOWCONTIG返回的數高,說明存在外部碎片。碎片的嚴重程度依賴於剛才顯示的值比估計值高多少。 擴展盤區開關數:該數應該等於掃描擴展盤區數減1。高了則說明有外部碎片。 每個擴展盤區上的平均頁數:該數是掃描頁數除以掃描擴展盤區數,一般是8。小於8說明有外部碎片。 掃描密度[最佳值:實際值]:DBCC SHOWCONTIG返回最有用的一個百分比。這是擴展盤區的最佳值和實際值的比率。該百分比應該盡可能靠近100%。低了則說明有外部碎片。 邏輯掃描碎片:無序頁的百分比。該百分比應該在0%到10%之間,高了則說明有外部碎片。 擴展盤區掃描碎片:無序擴展盤區在掃描索引葉級頁中所占的百分比。該百分比應該是0%,高了則說明有外部碎片。 每頁上的平均可用字節數:所掃描的頁上的平均可用字節數。越高說明有內部碎片,不過在你用這個數字決定是否有內部碎片之前,應該考慮fill factor(填充因子)。 平均頁密度(完整):每頁上的平均可用字節數的百分比的相反數。低的百分比說明有內部碎片。 整理數據庫碎片索引 看到如此不對勁,果斷去MSDN查找相關資料,找到了MSDN有對數據庫索引進行碎片整理的T
-SQL,執行了一下,發現效果還不錯。 使用 DBCC SHOWCONTIG 和 DBCC INDEXDEFRAG 對數據庫中的索引進行碎片整理:(以下示例將展示一種簡單的方法,對數據庫中碎片數量在聲明的閾值之上的所有索引進行碎片整理。) /*Perform a ‘USE <database name>‘ to select the database in which to run the script.*/ -- Declare variables SET NOCOUNT ON; DECLARE @tablename varchar(255); DECLARE @execstr varchar(400); DECLARE @objectid int; DECLARE @indexid int; DECLARE @frag decimal; DECLARE @maxfrag decimal; -- Decide on the maximum fragmentation to allow for. SELECT @maxfrag = 30.0; -- Declare a cursor. DECLARE tables CURSOR FOR SELECT TABLE_SCHEMA + . + TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = BASE TABLE; -- Create the table. CREATE TABLE #fraglist ( ObjectName char(255), ObjectId int, IndexName char(255), IndexId int, Lvl int, CountPages int, CountRows int, MinRecSize int, MaxRecSize int, AvgRecSize int, ForRecCount int, Extents int, ExtentSwitches int, AvgFreeBytes int, AvgPageDensity int, ScanDensity decimal, BestCount int, ActualCount int, LogicalFrag decimal, ExtentFrag decimal); -- Open the cursor. OPEN tables; -- Loop through all the tables in the database. FETCH NEXT FROM tables INTO @tablename; WHILE @@FETCH_STATUS = 0 BEGIN; -- Do the showcontig of all indexes of the table INSERT INTO #fraglist EXEC (DBCC SHOWCONTIG (‘‘‘ + @tablename + ‘‘‘) WITH FAST, TABLERESULTS, ALL_INDEXES, NO_INFOMSGS); FETCH NEXT FROM tables INTO @tablename; END; -- Close and deallocate the cursor. CLOSE tables; DEALLOCATE tables; -- Declare the cursor for the list of indexes to be defragged. DECLARE indexes CURSOR FOR SELECT ObjectName, ObjectId, IndexId, LogicalFrag FROM #fraglist WHERE LogicalFrag >= @maxfrag AND INDEXPROPERTY (ObjectId, IndexName, IndexDepth) > 0; -- Open the cursor. OPEN indexes; -- Loop through the indexes. FETCH NEXT FROM indexes INTO @tablename, @objectid, @indexid, @frag; WHILE @@FETCH_STATUS = 0 BEGIN; PRINT Executing DBCC INDEXDEFRAG (0, + RTRIM(@tablename) + , + RTRIM(@indexid) + ) - fragmentation currently + RTRIM(CONVERT(varchar(15),@frag)) + %; SELECT @execstr = DBCC INDEXDEFRAG (0, + RTRIM(@objectid) + , + RTRIM(@indexid) + ); EXEC (@execstr); FETCH NEXT FROM indexes INTO @tablename, @objectid, @indexid, @frag; END; -- Close and deallocate the cursor. CLOSE indexes; DEALLOCATE indexes; -- Delete the temporary table. DROP TABLE #fraglist; GO 執行後會返回索引掃描數、移動數、刪除數(Pages Scanned、Pages Moved、Pages Removed)。效果還是很明顯的,然後再把掃描結果進行比對: ----------------------------------------------------------------------------------------------------------------- DBCC SHOWCONTIG 正在掃描 UserInfo 表... 表: UserInfo (1646628909);索引 ID: 1,數據庫 ID: 7 已執行 TABLE 級別的掃描。 - 掃描頁數................................: 237 - 掃描區數..............................: 31 - 區切換次數..............................: 30 - 每個區的平均頁數........................: 7.6 - 掃描密度 [最佳計數:實際計數].......: 96.77% [30:31] - 邏輯掃描碎片 ..................: 2.95% - 區掃描碎片 ..................: 29.03% - 每頁的平均可用字節數.....................: 200.3 - 平均頁密度(滿).....................: 97.52% DBCC 執行完畢。如果 DBCC 輸出了錯誤信息,請與系統管理員聯系 ------------------------------------------------------------------------------------------------------------ 結果很有對比性,碎片大幅降低,每頁的平均可用字節數大幅降低,掃描密度提高,平均頁密度達到理想中的近飽和數值。看來DBCC的一些命令和MSDN的聯機叢書還是很不錯滴。雖然暫時降低了一些碎片指標,但只要有操作肯定也會有碎片產生,通過一段的時間跟蹤,才能對整體情況進行主觀的判斷。 相關鏈接:http://msdn.microsoft.com/zh-cn/library/ms188796.aspx http://msdn.microsoft.com/zh-cn/library/ms175008(v=sql.90).aspx

通過DBCC整理Sqlserver數據庫表索引碎片