USE [数据库]
GO
/****** Object: StoredProcedure [dbo].[IndexMaintenanceProcedure] Script Date: 2025-05-13 17:36:58 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[IndexMaintenanceProcedure]
AS
BEGIN
SET NOCOUNT ON;
DECLARE @schemaName NVARCHAR(128);
DECLARE @tableName NVARCHAR(128);
DECLARE @indexName NVARCHAR(128);
DECLARE @avg_fragmentation_in_percent FLOAT;
DECLARE @startTime DATETIME;
DECLARE @endTime DATETIME;
DECLARE @errorMessage NVARCHAR(MAX);
DECLARE @actionTaken NVARCHAR(50);
DECLARE @sql NVARCHAR(MAX);
-- 定义游标,获取所有碎片化超过5%的索引
DECLARE curIndexFrag CURSOR FOR
SELECT
s.name AS schema_name,
t.name AS table_name,
i.name AS index_name,
ips.avg_fragmentation_in_percent
FROM
sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
INNER JOIN
sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
INNER JOIN
sys.tables t ON i.object_id = t.object_id
INNER JOIN
sys.schemas s ON t.schema_id = s.schema_id
WHERE
i.name IS NOT NULL -- 排除堆(heap)
AND t.is_ms_shipped = 0 -- 排除系统表
AND ips.avg_fragmentation_in_percent > 5; -- 设置阈值
OPEN curIndexFrag;
FETCH NEXT FROM curIndexFrag INTO @schemaName, @tableName, @indexName, @avg_fragmentation_in_percent;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @startTime = GETDATE();
SET @errorMessage = NULL;
BEGIN TRY
IF @avg_fragmentation_in_percent >= 30
BEGIN
-- 碎片率高,重建索引
SET @actionTaken = 'Rebuild';
SET @sql = N'ALTER INDEX ' + QUOTENAME(@indexName) + N' ON '
+ QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + N' REBUILD;';
END
ELSE IF @avg_fragmentation_in_percent >= 5 AND @avg_fragmentation_in_percent < 30
BEGIN
-- 中度碎片,重组索引
SET @actionTaken = 'Reorganize';
SET @sql = N'ALTER INDEX ' + QUOTENAME(@indexName) + N' ON '
+ QUOTENAME(@schemaName) + N'.' + QUOTENAME(@tableName) + N' REORGANIZE;';
END
PRINT '执行操作: ' + @sql;
EXEC sp_executesql @sql;
END TRY
BEGIN CATCH
SET @errorMessage = ERROR_MESSAGE();
PRINT '错误发生: ' + @errorMessage;
END CATCH
SET @endTime = GETDATE();
-- 记录日志
INSERT INTO dbo.IndexMaintenanceLog (SchemaName, TableName, IndexName, Fragmentation, ActionTaken, StartTime, EndTime, ErrorMessage)
VALUES (@schemaName, @tableName, @indexName, @avg_fragmentation_in_percent, @actionTaken, @startTime, @endTime, @errorMessage);
FETCH NEXT FROM curIndexFrag INTO @schemaName, @tableName, @indexName, @avg_fragmentation_in_percent;
END
SELECT count(1) as cnt FROM dbo.IndexMaintenanceLog WHERE EndTime >= @startTime;
CLOSE curIndexFrag;
DEALLOCATE curIndexFrag;
END