Rat*_*ddy 6 sql-server sql-server-2016 index-maintenance
我的数据库大约是 2.5TB。每天运行重建索引是一个好习惯吗?
我们每天删除大约 20 GB 的数据 & 同时我们删除分区 & 我们将添加新分区。运行重建索引需要 8 小时,有时需要 24 小时。在此期间,日志文件增加到 300 GB。
我们需要将数据库碎片的每日报告发送给客户。看到 99% 或 98% 的人都会害怕。请建议。
表大小为 70GB,对于此表碎片级别,每天将是 99%。不知道是什么让客户要求每日报告碎片级别,但他每天都需要它。
小智 6
首先,您应该考虑page_count
索引的 。如果page_count
小于 1000(或您决定的任何值),那么您应该忽略 index。
我们有一个维护脚本来分析page_count
索引的碎片并遵循以下准则:-
ALTER INDEX … REORGANIZE
)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
Run Code Online (Sandbox Code Playgroud)
这一切都取决于您的要求。如果您每周只重建一次,对性能有何影响?你能在重建后每周发送一次报告吗?我会在测试环境(如果可能)中对性能进行基准测试,如果它不会降级太多,则每周只执行一次索引维护。
代理工作可能是这样的:-
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
Run Code Online (Sandbox Code Playgroud)