Sql-Server
數據庫維護每天重建索引
我的數據庫大約 2.5TB。每天執行重建索引是一個好習慣嗎?
我們每天刪除大約 20 GB 的數據,同時我們刪除分區,我們將添加新分區。執行重建索引需要 8 小時,有時需要 24 小時。在此期間,日誌文件增加到 300 GB。
我們需要每天向客戶發送數據庫碎片報告。看到 99% 或 98%,他們會害怕。請建議。
表大小為 70GB,對於此表碎片級別,每天將達到 99%。不知道是什麼讓客戶要求提供碎片級別的每日報告,但他每天都需要它。
首先,您應該考慮
page_count
索引的。如果page_count
小於 1000 (或您決定的任何值),那麼您應該忽略 index。我們有一個維護腳本,它分析
page_count
索引的碎片並遵循以下準則:-
- 少於 10% 的邏輯碎片,不做任何事情
- 10% 到 30% 之間的邏輯碎片,重新組織它(使用
ALTER INDEX … REORGANIZE
)- 超過 30% 的邏輯碎片,重建它(使用
ALTER INDEX … REBUILD
)(ONLINE= ON
對於企業版)這是了解您目前所在位置的入門:-
SELECT dbtables.[name] AS 'Table' ,dbindexes.[name] AS 'Index' ,indexstats.avg_fragmentation_in_percent ,CASE WHEN indexstats.avg_fragmentation_in_percent < 10 THEN 'NOTHING' WHEN indexstats.avg_fragmentation_in_percent >= 10 AND indexstats.avg_fragmentation_in_percent < 30 THEN 'REORGANIZE' WHEN indexstats.avg_fragmentation_in_percent >= 30 THEN 'REBUILD' END ,indexstats.page_count FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats INNER JOIN sys.tables dbtables ON dbtables.[object_id] = indexstats.[object_id] INNER JOIN sys.schemas dbschemas ON dbtables.[schema_id] = dbschemas.[schema_id] INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id] AND indexstats.index_id = dbindexes.index_id WHERE indexstats.database_id = DB_ID() AND page_count > 1000 AND dbindexes.NAME IS NOT NULL ORDER BY indexstats.avg_fragmentation_in_percent DESC
這一切都取決於您的要求。如果您每週只重建一次,性能會受到怎樣的影響?您可以在重建後直接每週發送一次報告嗎?我會在測試環境中設定性能基準(如果可能的話),如果它不會降低太多,那麼每週只執行一次索引維護。
代理工作可能是這樣的:-
DECLARE @Indexes AS TABLE ( ID INT IDENTITY(1, 1) NOT NULL ,TableNm VARCHAR(500) NOT NULL ,IndexNm VARCHAR(500) NOT NULL ,FragPerc DECIMAL(16, 3) NOT NULL ,RecAction VARCHAR(50) NOT NULL ,PageCount INT NOT NULL ) INSERT INTO @Indexes SELECT dbtables.[name] AS 'Table' ,dbindexes.[name] AS 'Index' ,indexstats.avg_fragmentation_in_percent ,CASE WHEN indexstats.avg_fragmentation_in_percent < 10 --change all levels to your requirement THEN 'NOTHING' WHEN indexstats.avg_fragmentation_in_percent >= 10 AND indexstats.avg_fragmentation_in_percent < 30 THEN 'REORGANIZE' WHEN indexstats.avg_fragmentation_in_percent >= 30 THEN 'REBUILD' END ,indexstats.page_count FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats INNER JOIN sys.tables dbtables ON dbtables.[object_id] = indexstats.[object_id] INNER JOIN sys.schemas dbschemas ON dbtables.[schema_id] = dbschemas.[schema_id] INNER JOIN sys.indexes AS dbindexes ON dbindexes.[object_id] = indexstats.[object_id] AND indexstats.index_id = dbindexes.index_id WHERE indexstats.database_id = DB_ID() AND page_count > 1000 AND dbindexes.NAME IS NOT NULL ORDER BY indexstats.avg_fragmentation_in_percent DESC DELETE FROM @Indexes WHERE RecAction = 'NOTHING' DECLARE @sql AS VARCHAR(MAX) DECLARE @whilecount AS INT = 1 DECLARE @rowcount AS INT = ( SELECT MAX(ID) FROM @Indexes ) DECLARE @IndexNm AS VARCHAR(500) DECLARE @TableNm AS VARCHAR(500) DECLARE @RecAction AS VARCHAR(50) WHILE @whilecount <= @rowcount BEGIN SET @IndexNm = ( SELECT IndexNm FROM @Indexes WHERE ID = @whilecount ) SET @TableNm = ( SELECT TableNm FROM @Indexes WHERE ID = @whilecount ) SET @RecAction = ( SELECT RecAction FROM @Indexes WHERE ID = @whilecount ) IF @RecAction = 'REBUILD' BEGIN SET @sql = 'ALTER INDEX [' + @IndexNm + '] ON [' + @TableNm + '] REBUILD WITH (FILLFACTOR = 98, ONLINE = ON);' --change depending on SQL version END ELSE IF @RecAction = 'REORGANIZE' BEGIN SET @sql = 'ALTER INDEX [' + @IndexNm + '] ON [' + @TableNm + '] REORGANIZE;' END EXECUTE (@sql); SET @whilecount += 1 END