SQL Server データベースを改善するための SSW ルールには、完全なデータベース メンテナンス プランの例があります: SSW。この例では、インデックスの再編成、インデックスの再構築、統計の更新の両方を実行しています。これには何か意味がありますか?Reorganize Index は Rebuild Index の高速ですが効果の低いバージョンだと思いましたか? また、インデックスの再構築により、統計も自動的に更新されます (少なくともクラスター化されたインデックスでは)。
9 に答える
再編成と再構築は別物です。
再編成: インデックスのデフラグです。既存のインデックスを取得し、既存のページを最適化します。ただし、ページが連続していない場合は、以前のままです。ページの内容のみが変更されます。
再構築: 実際には、インデックスを削除し、最初から再構築します。これは、最適化された連続したページを含む、まったく新しいインデックスを取得することを意味します。
さらに、再構築を使用すると、パーティションまたはファイル グループを変更できますが、再編成を使用すると、インデックス全体だけでなく、インデックスの 1 つのパーティションのみを最適化できます。
統計の更新は、クラスター化インデックスでは自動ですが、非クラスター化インデックスでは自動ではありません。
インデックスのメンテナンスを検討する前に、次の 2 つの主な質問に答えることが重要です。
- 断片化の程度は?
- 適切な行動は何ですか?再編成か再構築か?
この記事http://solutioncenter.apexsql.com/why-when-and-how-to-rebuild-and-reorganize-sql-server-indexes/で説明されているように、インデックスの再構築を実行する必要があるかどうかを判断するのに役立ちます。インデックスの再編成については、次の点をご理解ください。
インデックスの再編成は、SQL Server が既存のインデックスを調べてクリーンアップするプロセスです。インデックスの再構築は、インデックスが削除された後、まったく新しい構造でゼロから再作成され、積み上げられたフラグメントや空のページがすべて解放されるという負荷の高いプロセスです。
インデックスの再編成は、影響を受けるテーブルやビューをロックアウトせずにシステムの状態をそのままにしておく純粋なクリーンアップ操作ですが、再構築プロセスでは、影響を受けるテーブルが再構築期間全体にわたってロックされます。いくつかの環境。これを念頭に置いて、インデックスの再構築が「より強力な」ソリューションを備えたプロセスであることは明らかですが、影響を受けるインデックス付きテーブルが長時間ロックされる可能性があるという代償が伴います。
一方、インデックスの再編成は「軽量」のプロセスであり、効果の低い方法で断片化を解決します。クリーンなインデックスは、完全にゼロから作成された新しいインデックスに常に次ぐためです。ただし、インデックスの再編成は、操作中に影響を受けるインデックス付きテーブルをロックしないため、効率の観点からははるかに優れています。
上記の記事では、SSMS、T-SQL (テーブル内のインデックスを再編成/再構築するため)、および ApexSQL Backup と呼ばれるサードパーティ ツールを使用してインデックスを再編成および再構築する方法についても説明しています。
同じインデックスに対して a を実行してからREORGANIZE
aを実行しても意味がありません。REBUILD
REORGANIZE
REBUILD
それよりも悪いのは、SSW のメンテナンス プラン ダイアグラムでは、SHRINK
スペースを解放する方法の副作用としてインデックスを断片化する最初の処理を実行することです。次に、操作REBUILD
中の作業領域として、データベース ファイルにより多くの領域が再度割り当てられますREBUILD
。
REORGANIZE
余分な作業スペースをほとんど使用せずに、クラスター化または非クラスター化インデックス ページのリーフ ページをページごとに最適化するオンライン操作です。REBUILD
Enterprise エディションではオンライン操作であり、他のエディションではオフライン操作であり、インデックス サイズと同じ余分な作業領域を再び使用します。インデックスの新しいコピーを作成してから古いものを削除することで、断片化を解消します。デフォルトでは、この操作の一部として統計が再計算されますが、これは無効にすることができます。
詳細については、インデックスの再編成と再構築を参照してください。
SHRINK
オプションを除いて使用しないでくださいTRUNCATEONLY
。それでもファイルが再び大きくなる場合は、それが必要かどうかをよく考えてください。
インデックスの再編成を行うときに、インデックスが 2 つ以上の物理ファイルにまたがっている場合、データはデータ ファイル内でのみ最適化されます。ページは、あるデータ ファイルから別のデータ ファイルに移動されません。
インデックスが単一のファイルにある場合、reorg と reindex の最終結果は同じになります。
インデックスの断片化の程度によっては、reorg が高速になる場合もあれば、reindex が高速になる場合もあります。インデックスの断片化が少ないほど再編成は高速になり、断片化が進むほど再編成は遅くなりますが、再インデックスは高速になります。
ビリさんの言うとおりです。データベース全体のインデックスを再作成する方法は次のとおりです。
EXEC [sp_MSforeachtable] @command1="RAISERROR('DBCC DBREINDEX(''?'') ...',10,1) WITH NOWAIT DBCC DBREINDEX('?')"
このSPを使う
CREATE PROCEDURE dbo.[IndexRebuild]
AS
DECLARE @TableName NVARCHAR(500);
DECLARE @SQLIndex NVARCHAR(MAX);
DECLARE @RowCount INT;
DECLARE @Counter INT;
DECLARE @IndexAnalysis TABLE
(
AnalysisID INT IDENTITY(1, 1)
NOT NULL
PRIMARY KEY ,
TableName NVARCHAR(500) ,
SQLText NVARCHAR(MAX) ,
IndexDepth INT ,
AvgFragmentationInPercent FLOAT ,
FragmentCount BIGINT ,
AvgFragmentSizeInPages FLOAT ,
PageCount BIGINT
)
BEGIN
INSERT INTO @IndexAnalysis
SELECT [objects].name ,
'ALTER INDEX [' + [indexes].name + '] ON ['
+ [schemas].name + '].[' + [objects].name + '] '
+ ( CASE WHEN ( [dm_db_index_physical_stats].avg_fragmentation_in_percent >= 20
AND [dm_db_index_physical_stats].avg_fragmentation_in_percent < 40
) THEN 'REORGANIZE'
WHEN [dm_db_index_physical_stats].avg_fragmentation_in_percent > = 40
THEN 'REBUILD'
END ) AS zSQL ,
[dm_db_index_physical_stats].index_depth ,
[dm_db_index_physical_stats].avg_fragmentation_in_percent ,
[dm_db_index_physical_stats].fragment_count ,
[dm_db_index_physical_stats].avg_fragment_size_in_pages ,
[dm_db_index_physical_stats].page_count
FROM [sys].[dm_db_index_physical_stats](DB_ID(), NULL, NULL,
NULL, 'LIMITED') AS [dm_db_index_physical_stats]
INNER JOIN [sys].[objects] AS [objects] ON ( [dm_db_index_physical_stats].[object_id] = [objects].[object_id] )
INNER JOIN [sys].[schemas] AS [schemas] ON ( [objects].[schema_id] = [schemas].[schema_id] )
INNER JOIN [sys].[indexes] AS [indexes] ON ( [dm_db_index_physical_stats].[object_id] = [indexes].[object_id]
AND [dm_db_index_physical_stats].index_id = [indexes].index_id
)
WHERE index_type_desc <> 'HEAP'
AND [dm_db_index_physical_stats].avg_fragmentation_in_percent > 20
END
SELECT @RowCount = COUNT(AnalysisID)
FROM @IndexAnalysis
SET @Counter = 1
WHILE @Counter <= @RowCount
BEGIN
SELECT @SQLIndex = SQLText
FROM @IndexAnalysis
WHERE AnalysisID = @Counter
EXECUTE sp_executesql @SQLIndex
SET @Counter = @Counter + 1
END
GO
この SP を毎週実行する 1 つのジョブを作成します。
さらに良いのは:
EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REINDEX'
また
EXEC sp_MSforeachtable 'ALTER INDEX ALL ON ? REORGANIZE'
私の 2 セント... この方法は、tech net で概説されている仕様に従います: http://technet.microsoft.com/en-us/library/ms189858(v=sql.105).aspx
USE [MyDbName]
GO
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
CREATE PROCEDURE [maintenance].[IndexFragmentationCleanup]
AS
DECLARE @reIndexRequest VARCHAR(1000)
DECLARE reIndexList CURSOR
FOR
SELECT INDEX_PROCESS
FROM (
SELECT CASE
WHEN avg_fragmentation_in_percent BETWEEN 5
AND 30
THEN 'ALTER INDEX [' + i.NAME + '] ON [' + t.NAME + '] REORGANIZE;'
WHEN avg_fragmentation_in_percent > 30
THEN 'ALTER INDEX [' + i.NAME + '] ON [' + t.NAME + '] REBUILD with(ONLINE=ON);'
END AS INDEX_PROCESS
,avg_fragmentation_in_percent
,t.NAME
FROM sys.dm_db_index_physical_stats(NULL, NULL, NULL, NULL, NULL) AS a
INNER JOIN sys.indexes AS i ON a.object_id = i.object_id
AND a.index_id = i.index_id
INNER JOIN sys.tables t ON t.object_id = i.object_id
WHERE i.NAME IS NOT NULL
) PROCESS
WHERE PROCESS.INDEX_PROCESS IS NOT NULL
ORDER BY avg_fragmentation_in_percent DESC
OPEN reIndexList
FETCH NEXT
FROM reIndexList
INTO @reIndexRequest
WHILE @@FETCH_STATUS = 0
BEGIN
BEGIN TRY
PRINT @reIndexRequest;
EXEC (@reIndexRequest);
END TRY
BEGIN CATCH
DECLARE @ErrorMessage NVARCHAR(4000);
DECLARE @ErrorSeverity INT;
DECLARE @ErrorState INT;
SELECT @ErrorMessage = 'UNABLE TO CLEAN UP INDEX WITH: ' + @reIndexRequest + ': MESSAGE GIVEN: ' + ERROR_MESSAGE()
,@ErrorSeverity = 9
,@ErrorState = ERROR_STATE();
END CATCH;
FETCH NEXT
FROM reIndexList
INTO @reIndexRequest
END
CLOSE reIndexList;
DEALLOCATE reIndexList;
RETURN 0
GO