多数のテーブルが作成および削除されるデータベースがいくつかあります。 SQL Serverは システムベーステーブル の内部メンテナンスを行っていません。つまり、時間の経過とともに断片化し、サイズが大きくなる可能性があります。これにより、バッファプールに不必要な圧力がかかり、データベース内のすべてのテーブルのサイズを計算するなどの操作のパフォーマンスに悪影響を及ぼします。
これらのコア内部テーブルの断片化を最小限に抑えるための提案はありますか?明白な解決策の1つは、非常に多くのテーブルを作成しないようにする(またはtempdbにすべての一時テーブルを作成する)ことですが、この質問のために、アプリケーションにはその柔軟性がないとしましょう。
編集:詳細な調査により、これは 未回答の質問 であることがわかります。これは密接に関連しており、ALTER INDEX...REORGANIZE
を介した何らかの手作業によるメンテナンスがオプションである可能性があることを示しています。
初期調査
これらのテーブルに関するメタデータは sys.dm_db_partition_stats
で表示できます:
-- The system base table that contains one row for every column in the system
SELECT row_count,
(reserved_page_count * 8 * 1024.0) / row_count AS bytes_per_row,
reserved_page_count/128. AS space_mb
FROM sys.dm_db_partition_stats
WHERE object_id = OBJECT_ID('sys.syscolpars')
AND index_id = 1
-- row_count: 15,600,859
-- bytes_per_row: 278.08
-- space_mb: 4,136
ただし、 sys.dm_db_index_physical_stats
は、これらのテーブルの断片化の表示をサポートしていないようです。
-- No fragmentation data is returned by sys.dm_db_index_physical_stats
SELECT *
FROM sys.dm_db_index_physical_stats(
DB_ID(),
OBJECT_ID('sys.syscolpars'),
NULL,
NULL,
'DETAILED'
)
Ola Hallengrenのスクリプト には、is_ms_shipped = 1
オブジェクトのデフラグを検討するためのパラメーターも含まれていますが、このパラメーターを有効にしても、プロシージャはシステムベーステーブルを暗黙的に無視します。 Olaは、これが予想される動作であることを明確にしました。 ms_shipped(msdb.dbo.backupset
など)のユーザーテーブル(システムテーブルではない)のみが考慮されます。
-- Returns code 0 (successful), but does not do any work for system base tables.
-- Instead of the expected commands to update statistics and reorganize indexes,
-- no commands are generated. The script seems to assume the target tables will
-- appear in sys.tables, but this does not appear to be a valid assumption for
-- system tables like sys.sysrowsets or sys.syscolpars.
DECLARE @result int;
EXEC @result = IndexOptimize @Databases = 'Test',
@FragmentationLow = 'INDEX_REORGANIZE',
@FragmentationMedium = 'INDEX_REORGANIZE',
@FragmentationHigh = 'INDEX_REORGANIZE',
@PageCountLevel = 0,
@UpdateStatistics = 'ALL',
@Indexes = '%Test.sys.sysrowsets.%',
-- Proc works properly if targeting a non-system table instead
--@Indexes = '%Test.dbo.Numbers.%',
@MSShippedObjects = 'Y',
@Execute = 'N';
PRINT(@result);
追加のリクエストされた情報
システムテーブルバッファープールの使用状況の検査の下でAaronのクエリの適応を使用しました。これにより、1つのデータベースのバッファープールに数十GBのシステムテーブルがあり、場合によってはそのスペースの約80%が空きスペースであることがわかりました。
-- Compute buffer pool usage by system table
SELECT OBJECT_NAME(p.object_id),
COUNT(b.page_id) pages,
SUM(b.free_space_in_bytes/8192.0) free_pages
FROM sys.dm_os_buffer_descriptors b
JOIN sys.allocation_units a
ON a.allocation_unit_id = b.allocation_unit_id
JOIN sys.partitions p
ON p.partition_id = a.container_id
AND p.object_id < 1000 -- A loose proxy for system tables
WHERE b.database_id = DB_ID()
GROUP BY p.object_id
ORDER BY pages DESC
このシステムテーブルを「バッファプールへの不必要な圧力であり、データベース内のすべてのテーブルのサイズの計算などの操作のパフォーマンスに悪影響を与える」唯一の原因として、確実かつ正確に特定しましたか?このシステムテーブルは、(a)断片化が最小限に抑えられるか、チェックされないように、または(b)最適化レベルが実際に大きな影響を与えないようにメモリ内で効率的に管理されるように、自己管理されていませんか?
使用中のページ数と、メモリにあるページの空き容量(page_free_space_percent
は、割り当てDMFでは常にNULL
ですが、これはバッファDMVから使用できます)-これは、あなたが何を心配しているのかを知るのに役立ちます本当に心配すべきことです:
SELECT
Number_of_Pages = COUNT(*),
Number_of_Pages_In_Memory = COUNT(b.page_id),
Avg_Free_Space = AVG(b.free_space_in_bytes/8192.0)
FROM sys.dm_db_database_page_allocations
(
DB_ID(),
OBJECT_ID(N'sys.syscolpars'),
NULL,NULL,'DETAILED'
) AS p
LEFT OUTER JOIN sys.dm_os_buffer_descriptors AS b
ON b.database_id = DB_ID()
AND b.page_id = p.allocated_page_page_id
AND b.file_id = p.allocated_page_file_id;
ページ数が少ない場合(システムテーブルの場合はおそらく<10000など)、または空き領域が「少ない」場合(reorg/rebuildの一般的なしきい値がわからない場合)、他のより興味深い、ぶら下がっている果物に焦点を当てます。
ページ数が多いかつ空き領域が "高い"場合は、OKです。SQLServerの自己保守にクレジットが多すぎると思います。 他の質問 から示したように、これは機能します...
ALTER INDEX ALL ON sys.syscolpars REORGANIZE;
...とdoes断片化を減らします。昇格されたアクセス許可が必要になる場合があります(私は牡丹としては試しませんでした)。
自分のメンテナンスの一環として定期的にこれを行うだけでよい場合があります。気分が良くなった場合や、システムにプラスの影響があるという証拠がある場合です。
アーロンの回答からのガイダンスと追加の調査に基づいて、これが私が取ったアプローチの簡単な説明です。
私が言えることから、システムベーステーブルの断片化を検査するためのオプションは限られています。私は先に進み、より良い可視性を提供するために 接続の問題 を提出しましたが、それまでの間、オプションにはバッファープールの調査や行あたりの平均バイト数のチェックなどが含まれているようです。
次に すべてのシステムベーステーブルで `ALTER INDEX ... REORGANIZEを実行する手順 を作成しました。この手順を最も(ab)使用されている開発サーバーのいくつかで実行すると、システムベーステーブルの累積サイズが最大50GB削減されました(システム上に約5MMのユーザーテーブルがあるため、明らかに極端なケースです)。
さまざまな単体テストおよび開発によって作成されたユーザーテーブルの多くをクリーンアップするのに役立つ夜間のメンテナンスタスクの1つは、以前は完了するまでに50分かかりました。 sp_whoisactive
、 sys.dm_os_waiting_tasks
、およびDBCC PAGE
の組み合わせは、待機がシステムベーステーブルのI/Oによって支配されていることを示していました。
すべてのシステムベーステーブルの再編成後、メンテナンスタスクは約15分に減少しました。まだI/O待機がいくつかありましたが、おそらくキャッシュに残っているデータの量が多かったか、断片化が少ないため先読みが多かったため、大幅に減少しました。
したがって、私の結論は、システムベーステーブルのALTER INDEX...REORGANIZE
を保守計画に追加することは検討に役立つかもしれないということですが、データベース上に異常な数のオブジェクトが作成されるシナリオがある場合に限られます。