私はすべてのサーバーでOla Hallengrenスクリプトを実行して、インデックスと統計のメンテナンスを行います。コマンドログテーブルを見ると、コマンドが終了してから次のコマンドが開始されるまでに長い時間がかかります。このギャップは1時間を超える場合があります。
他の誰かが自分のシステムでこれを観察していますか?維持するアイテム間の(私が推測している)発見時間を短縮するために私ができることはありますか?以下は、一緒に実行しているパラメーターセットです。
sqlcmd -E -S $(ESCAPE_SQUOTE(SRVR)) -d master -Q "EXECUTE [dbo].[IndexOptimize]
@Databases = 'USER_DATABASES',
@LogToTable = 'Y',
@FragmentationLow = NULL,
@FragmentationMedium = 'INDEX_REORGANIZE,INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationHigh = 'INDEX_REBUILD_ONLINE,INDEX_REBUILD_OFFLINE',
@FragmentationLevel1 = 50,
@FragmentationLevel2 = 80,
@UpdateStatistics = 'ALL',
@OnlyModifiedStatistics = 'Y' " -b
だから私がこれを実行すると:
SELECT DATEDIFF(MINUTE, cl.StartTime, cl.EndTime)
, *
FROM master.dbo.CommandLog AS cl
WHERE cl.StartTime > '2014-12-13'
ORDER BY cl.ID
私はこれを見る:
根本的な原因はDMF sys.dm_db_index_physical_stats
をスキャンモードおよびヒープと組み合わせて使用します。
(私の強調[〜#〜]制限[〜#〜]元の説明の一部)
関数が実行されるモードは、関数が使用する統計データを取得するために実行されるスキャンのレベルを決定します。モードはLIMITED、SAMPLED、またはDetailedとして指定されます。この関数は、テーブルまたはインデックスの指定されたパーティションを構成するアロケーションユニットのページチェーンを横断します。 sys.dm_db_index_physical_statsは、実行モードに関係なく、インテント共有(IS)テーブルロックのみを必要とします。
LIMITEDモードは最速のモードであり、スキャンするページ数が最小です。インデックスの場合、Bツリーの親レベルのページ(つまり、リーフレベルより上のページがスキャンされます。 ヒープの場合、関連するPFSおよびIAMページが検査され、ヒープのデータページがLIMITEDモードでスキャンされます。
LIMITEDモードでは、データベースエンジンはBツリーの非リーフページとヒープのIAMおよびPFSページのみをスキャンするため、compressed_page_countはNULLです。 SAMPLEDモードを使用して、compressed_page_countの推定値を取得し、DETAILEDモードを使用して、compression_page_countの実際の値を取得します。 SAMPLEDモードは、インデックスまたはヒープ内のすべてのページの1%サンプルに基づいて統計を返します。 SAMPLEDモードでの結果は、概算と見なす必要があります。インデックスまたはヒープのページ数が10,000未満の場合、SAMPLEDの代わりにDetailedモードが使用されます。
Detailedモードはすべてのページをスキャンし、すべての統計を返します。
各モードで実行される作業が増えるため、モードはLIMITEDからDetailedに徐々に遅くなります。テーブルまたはインデックスのサイズまたは断片化レベルをすばやく測定するには、LIMITEDモードを使用します。これは最速であり、インデックスのIN_ROW_DATAアロケーションユニットの各非リーフレベルの行を返しません。
参照:sys.dm_db_index_physical_stats(Transact-SQL )|スキャンモード (Microsoft Docs)
Olaのスクリプトがsys.dm_db_index_physical_stats
LIMITED
モードでは、データの量によっては、非常に大きなヒープをスキャンするのに長い時間がかかる場合があります。そして、あなたは@UpdateStatistics = 'ALL'
ヒープ列の統計を含むすべての統計(INDEX
およびCOLUMN
)を更新するようにスクリプトに指示しています。
すべてのオブジェクトの統計を更新するのではなく、スコープをINDEX
に制限するか、次のパラメーターの変更を検討することをお勧めします。
@OnlyModifiedStatistics = 'Y'
デフォルトはN
です
最新の統計更新以降に行が変更されている場合にのみ、統計を更新します。
参照:SQL Serverインデックスと統計のメンテナンス (ola.hallengren.com)
これについて少し掘り下げて、一般的なクエリを使用してインデックスの断片化を取得すると、1.5 TBのデータベースで160行を返す場合でも、約1時間かかりました。
SELECT s.name AS schemaname ,
t.name AS tablename ,
t.object_id ,
i.name AS indexname ,
i.index_id ,
x.page_count ,
x.avg_fragmentation_in_percent ,
x.avg_page_space_used_in_percent ,
i.type_desc
FROM sys.dm_db_index_physical_stats(DB_ID(
), NULL, NULL, NULL, 'LIMITED') x
INNER JOIN sys.tables t ON x.object_id = t.object_id
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.indexes i ON x.object_id = i.object_id
AND x.index_id = i.index_id
WHERE x.index_id > 0
AND alloc_unit_type_desc = 'IN_ROW_DATA'
AND x.page_count > 1000;
これにより、インデックスメンテナンスルーチンのこの部分が実行されると、新しいデータベースの開始時に、初期情報を収集してコマンドをビルドするのに非常に長い時間がかかると思います。
SET @CurrentCommand12 = @CurrentCommand12 +
'SELECT @ParamFragmentationLevel = MAX(avg_fragmentation_in_percent),
@ParamPageCount = SUM(page_count)
FROM sys.dm_db_index_physical_stats(
@ParamDatabaseID, @ParamObjectID, @ParamIndexID, @ParamPartitionNumber, ''LIMITED'')
WHERE alloc_unit_type_desc = ''IN_ROW_DATA'' AND index_level = 0'
EXECUTE sp_executesql @statement = @CurrentCommand12, @params = N'@ParamDatabaseID int,
@ParamObjectID int, @ParamIndexID int, @ParamPartitionNumber int,
@ParamFragmentationLevel float OUTPUT, @ParamPageCount bigint OUTPUT',
@ParamDatabaseID= @CurrentDatabaseID, @ParamObjectID = @CurrentObjectID, @ParamIndexID =
@CurrentIndexID, @ParamPartitionNumber = @CurrentPartitionNumber,
@ParamFragmentationLevel = @CurrentFragmentationLevel OUTPUT, @ParamPageCount =
@CurrentPageCount OUTPUT
オンラインで再構築している場合でも、この動作を確認しましたが、インデックスを変更するにはスキーマ変更(SCH-M)ロックが必要です。
忙しいテーブルでは、取得に時間がかかる場合があります。