SQL Serverシステムテーブルは最適化できますか?


15

多数のテーブルが作成および削除されるデータベースがいくつかあります。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オブジェクトの最適化を考慮するパラメーターも含まれていますが、このパラメーターが有効になっている場合でも、プロシージャはシステムベーステーブルを静かに無視します。オラは、これが予想される動作であることを明らかにしました。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);


追加のリクエスト情報

システムテーブルバッファープールの使用状況を検査する下でアーロンのクエリの適応を使用し、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

ここに画像の説明を入力してください

回答:


11

このシステムテーブルを、「バッファプールへの不必要な負荷と、データベース内のすべてのテーブルのサイズの計算などの操作のパフォーマンスに悪影響を及ぼす」唯一の原因として明確かつ正確に特定しましたか?このシステムテーブルは、(a)断片化を最小限に抑えるか、密かにチェックする、または(b)最適化をメモリ内で効率的に管理して、最適化レベルが実際に大きな影響を与えないような方法で自己管理されていませんか?

使用中のページ数を確認でき、メモリ内のページの空き容量を確認できますpage_free_space_percent常にNULL割り当てDMFにありますが、これバッファ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未満)、または空き領域が「低い」場合(通常の再編成/再構築のしきい値がわからない)、他の、より興味深い、ハングアップの少ない果物に焦点を当てます。

ページのあなたの数が多い場合空き領域が「高」で、[OK]を、多分私は、独自のセルフメンテナンスのためにSQL Serverのあまり信用を与えています。他の質問で示したように、これは機能します...

ALTER INDEX ALL ON sys.syscolpars REORGANIZE;

...と、断片化を減らします。昇格されたアクセス許可が必要な場合がありますが(私はペオンとしては試しませんでした)。

気分が良くなる、および/またはシステムにプラスの影響があるという証拠がある場合は、自分のメンテナンスの一環として定期的にこれを行うことができます。


私たちがやったことをまとめた別の回答を追加し、ここで以前のコメントを整理しました。ご協力ありがとうございます!
ジェフパターソン

7

アーロンの回答からのガイダンスと追加の調査に基づいて、私が取ったアプローチの簡単な説明を以下に示します。

私が知ることができることから、システムベーステーブルの断片化を検査するためのオプションは限られています。私は先に進み、より良い可視性を提供するためにConnectの問題を提出しましたが、その間、オプションにはバッファープールの検査や行ごとの平均バイト数のチェックなどが含まれているようです。

次に、すべてのシステムベーステーブルで「ALTER INDEX ... REORGANIZE」を実行するプロシージャを作成しました。最も(ab)使用されているいくつかの開発サーバーでこの手順を実行すると、システムベーステーブルの累積サイズが最大50GB削減されました(システム上に〜5MMのユーザーテーブルがあるため、明らかに極端なケースです)。

さまざまな単体テストおよび開発によって作成されたユーザーテーブルの多くをクリーンアップするのに役立つ夜間のメンテナンスタスクの1つは、以前は完了までに約50分かかっていました。、、およびの組み合わせはsp_whoisactive、待機がシステムベーステーブルのI / Oによって支配されていることsys.dm_os_waiting_tasksDBCC PAGE示しました。

すべてのシステムベーステーブルの再編成後、メンテナンスタスクは約15分に低下しました。I / Oの待機はまだありましたが、おそらくキャッシュに残っているデータの量が多かったため、および/または断片化が少ないため先読みが多かったために、大幅に減少しました。

したがって、私の結論は、ALTER INDEX...REORGANIZEシステムベーステーブルをメンテナンスプランに追加することは考慮に値するかもしれませんが、データベース上に異常な数のオブジェクトが作成されるシナリオがある場合にのみそうです。


あなたの質問と答えの両方に+1-内部は少しブラックボックスであり、あなたパフォーマンスのために本当に厄介なシナリオのように見えるものにいくつかの光を当てるのを助けました(あなたのエッジケースであっても)。
マックスヴァーノン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.