SQL Serverにて、断片化したインデックスのみを再構築(Rebuild)や再構成(Reorganize)する必要があり、その時使ったストアドプロシージャの備忘録です。
再構築(Rebuild)
CREATE PROCEDURE [dbo].[usp_RebuildFragmentedIndexed] @threshold FLOAT = 30.0 AS BEGIN SET NOCOUNT ON; DECLARE @base_sql NVARCHAR(max) DECLARE @edition NVARCHAR(max) SET @base_sql = 'ALTER INDEX @index_name On @table_name REBUILD @rebuild_index_option' SET @edition = CONVERT(NVARCHAR, SERVERPROPERTY('Edition')) SET @base_sql = REPLACE(@base_sql, '@rebuild_index_option', CASE WHEN PATINDEX('%Enterprise%', @edition) > 0 OR PATINDEX('%Developer%', @edition) > 0 THEN 'WITH (ONLINE=ON)' ELSE '' END) DECLARE CUR CURSOR FOR SELECT CONCAT_WS('.', QUOTENAME(S.name), QUOTENAME(O.name)) AS TableName , QUOTENAME(I.name) AS IndexName --, PS.avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED') AS PS INNER JOIN sys.objects AS O ON PS.object_id = O.object_id INNER JOIN sys.schemas AS S ON O.schema_id = S.schema_id INNER JOIN sys.indexes AS I ON PS.object_id = I.object_id AND PS.index_id = I.index_id WHERE avg_fragmentation_in_percent > @threshold AND PS.index_id > 0; DECLARE @table_name SYSNAME DECLARE @index_name SYSNAME --DECLARE @avg_fragmentation_in_percent FLOAT DECLARE @sql_command NVARCHAR(max) OPEN CUR FETCH NEXT FROM CUR INTO @table_name, @index_name --, @avg_fragmentation_in_percent WHILE @@FETCH_STATUS = 0 BEGIN SET @sql_command = REPLACE(REPLACE(@base_sql, '@index_name', @index_name), '@table_name', @table_name) --PRINT @sql_command EXECUTE sp_executesql @sql_command FETCH NEXT FROM CUR INTO @table_name, @index_name END CLOSE CUR DEALLOCATE CUR END
公式情報には、行ストアインデックスでの断片化を再構築する際の大まかな値として、avg_fragmentation_in_percent が30%より大きい場合を例示しています。
rebuild_index_option
ですが、SQL Server 2014より ONLINE = ON
が指定可能になっており、その際にはデフォルトで ONLINE = ON ( WAIT_AT_LOW_PRIORITY ( MAX_DURATION = 0 MINUTES, ABORT_AFTER_WAIT = NONE )
と解釈されます。
SQL Server 2017より RESUMABLE = ON
が指定可能となっており、ONLINE = ON
と同時に指定可能です。
再構成(Reorganize)
ALTER PROCEDURE [dbo].[usp_ReorganizeFragmentedIndexed] @threshold FLOAT = 5.0 AS BEGIN SET NOCOUNT ON; DECLARE @base_sql NVARCHAR(max) SET @base_sql = 'ALTER INDEX @index_name ON @table_name REORGANIZE' DECLARE CUR CURSOR FOR SELECT CONCAT_WS('.', QUOTENAME(S.name), QUOTENAME(O.name)) AS TableName , QUOTENAME(I.name) AS IndexName --, PS.avg_fragmentation_in_percent FROM sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, 'LIMITED') AS PS INNER JOIN sys.objects AS O ON PS.object_id = O.object_id INNER JOIN sys.schemas AS S ON O.schema_id = S.schema_id INNER JOIN sys.indexes AS I ON PS.object_id = I.object_id AND PS.index_id = I.index_id WHERE avg_fragmentation_in_percent >= @threshold AND PS.index_id > 0; DECLARE @table_name SYSNAME DECLARE @index_name SYSNAME --DECLARE @avg_fragmentation_in_percent FLOAT DECLARE @sql_command NVARCHAR(max) OPEN CUR FETCH NEXT FROM CUR INTO @table_name, @index_name --, @avg_fragmentation_in_percent WHILE @@FETCH_STATUS = 0 BEGIN SET @sql_command = REPLACE(REPLACE(@base_sql, '@index_name', @index_name), '@table_name', @table_name) --PRINT @sql_command EXECUTE sp_executesql @sql_command FETCH NEXT FROM CUR INTO @table_name, @index_name END CLOSE CUR DEALLOCATE CUR END
参考にした情報: