SQL Server

SQL SQLServer

SQL Serverインデックスメンテナンス完全ガイド

2025年9月26日

システムが静かに稼働を始める――サーバーが深く息を吸い、データの血流が滞りなく巡り始める、その瞬間はまるで生き物の呼吸を感じるようです。

しかし日々の更新や削除という波が繰り返されるたび、データベースの「呼吸」は少しずつ乱れ、秩序だった動きに小さな亀裂が生まれていきます。

最も目に見える兆候が、インデックスの断片化です。

断片化は静かに、しかし確実にクエリ応答を遅くし、CPUやI/Oリソースというシステムの心臓を蝕む――まさにパフォーマンスの暗殺者です。

気づかぬまま放置すれば、やがてシステム全体の生命力を奪いかねません。

この記事では、データの迷宮に潜む影の脅威を、制御する術をまとめています。

診断から予防、あなたはデータベースの奥深くに入り込み、その呼吸を再び整え、力強く滑らかに動かす秘策を手に入れることができるのです。

第1章|インデックス断片化のメカニズム

SQL Serverのデータは「ページ」という単位で物理格納されます。

インデックスはページが効率よく並ぶことで高速検索を実現しますが、INSERTUPDATEDELETEが繰り返されると以下が発生します。

  • ページ分割 (Page Split):新規データ挿入時にページが分割され、論理順序と物理格納順がズレる → 外部断片化
  • 空き領域の発生:削除や更新で空きが残る → 内部断片化

これにより余計なディスクI/Oが発生し、システムパフォーマンスを低下させます。

第2章|断片化の診断と指標

代表的指標

  • avg_fragmentation_in_percent:外部断片化率
  • page_count:インデックスサイズ。巨大テーブルでは断片化率が低くても影響大
  • avg_page_space_used_in_percent:内部断片化指標

診断クエリ(サンプル)

SELECT 
    OBJECT_SCHEMA_NAME(PS.object_id) AS schema_name,
    OBJECT_NAME(PS.object_id) AS table_name,
    IDX.name AS index_name,
    PS.avg_fragmentation_in_percent,
    PS.page_count,
    PS.avg_page_space_used_in_percent
FROM 
    sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL, 'SAMPLED') AS PS
LEFT JOIN sys.indexes AS IDX 
    ON PS.object_id = IDX.object_id AND PS.index_id = IDX.index_id
WHERE PS.index_id > 0
  AND PS.page_count > 100
ORDER BY PS.avg_fragmentation_in_percent DESC;

大規模DBのヒント: 全ページスキャン (DETAILED) は高負荷のため、まずは SAMPLED で確認。ページ数が数百万単位のテーブルは別スケジュールでメンテナンス推奨。

第3章|REORGANIZE と REBUILD の最適戦略

項目 REORGANIZE REBUILD
処理 ページデフラグ インデックス完全再作成
負荷
統計情報 更新されない 更新される
効果 外部断片化の解消 内外部断片化を完全解消
適用 軽微断片化(5〜30%) 深刻断片化(30%以上)

注意点(大規模DB)

  • ONLINE=ON はEnterprise Edition限定
  • REBUILD 時は tempdb とトランザクションログの増加に注意
  • 巨大テーブルでは断片化率15%でも REBUILD 検討が必要
  • メンテナンス時間を業務影響が少ない深夜・週末に設定

第4章|実践スクリプト(セットベース版)

大規模DBではカーソルよりセットベース処理が高速です。

以下は断片化率に応じて REORGANIZE/REBUILD を自動判断する例です。

WITH Targets AS (
    SELECT 
        PS.object_id,
        PS.index_id,
        PS.partition_number,
        PS.avg_fragmentation_in_percent,
        IDX.name AS index_name,
        OBJECT_SCHEMA_NAME(PS.object_id) AS schema_name,
        OBJECT_NAME(PS.object_id) AS table_name
    FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'SAMPLED') PS
    JOIN sys.indexes IDX
        ON PS.object_id = IDX.object_id AND PS.index_id = IDX.index_id
    WHERE PS.index_id > 0
      AND PS.page_count >= 100
)
SELECT *,
    CASE 
        WHEN avg_fragmentation_in_percent >= 30 THEN 'REBUILD'
        WHEN avg_fragmentation_in_percent >= 5 THEN 'REORGANIZE'
    END AS Action
INTO #TargetsToMaintain
FROM Targets
WHERE avg_fragmentation_in_percent >= 5;

-- 動的SQLで一括処理
DECLARE @sql NVARCHAR(MAX);
SELECT @sql = STRING_AGG(
    'ALTER INDEX [' + index_name + '] ON [' + schema_name + '].[' + table_name + '] ' + Action + 
    CASE WHEN Action='REBUILD' THEN ' WITH (ONLINE = ON, SORT_IN_TEMPDB = ON);' ELSE ';' END
, CHAR(10))
FROM #TargetsToMaintain;

EXEC sp_executesql @sql;
DROP TABLE #TargetsToMaintain;

ポイント: カーソルを避けることで、大規模DBでも短時間で処理可能。

負荷軽減したい場合、特定スキーマやテーブルに絞る。バッチ処理にする。実行順を断片化率の高い順にして、時間切れになっても優先度の高いものから処理。などが考えられます。

第5章|断片化予防と FILLFACTOR

  • 高頻度更新テーブルでは FILLFACTOR=80〜90 を設定
  • ページに余裕を持たせることでページ分割を減らし、断片化進行を抑制
CREATE INDEX IX_YourIndex ON YourTable(YourColumn)
WITH (FILLFACTOR = 85);
  • 注意: 空き領域が増えるためストレージ効率は低下。更新頻度に応じて調整。

第6章|運用自動化とモニタリング

  • SQL Server エージェントで夜間・週末にジョブ化
  • メンテナンス後は sys.dm_db_index_usage_statssys.dm_db_index_physical_stats で効果確認
  • REBUILD で tempdb/log 増加が発生する場合は、事前に容量監視

まとめ(大規模DB向けポイント)

  1. 診断sys.dm_db_index_physical_stats で定期確認
  2. 解消:セットベースで REORGANIZE / REBUILD を戦略的に適用
  3. 予防:FILLFACTORでページ分割を抑制
  4. 自動化:ジョブ化&リソース監視で安全運用

サイクルを確立することで、大規模DBでも安定したパフォーマンスを維持できます。

今日の一杯

天領酒造 天領

今日の一杯 日本酒

2025/9/1

純米酒 天領 レビュー|今日の一杯 日本酒

岐阜県・飛騨高山の老舗酒蔵「天領酒造」の純米酒。 飛騨地方は江戸時代に幕府の直轄地(天領)とされていた土地です。 この「天領」という名前、ピンときた方もいるのでは?そう、かつてゲームボーイで発売された『メダロット2』の主人公、「天領イッキ」の由来になっているお酒です。 どんなお酒? 今回飲んだのは、天領酒造さんの定番純米酒。 岐阜のブランド米「ひだほまれ」を使用し、軟水仕込みで丁寧に造られた一本です。 味わい:ほんのりとした米の甘みと、すっきりとした後味が特徴。冷やしても良いけれど、ぬる燗(42℃前後)で ...

続きを読む

今日の一杯 赤ワイン

2025/7/7

フェウド・アランチョ ネロ・ダーヴォラ レビュー|今日の一杯 赤ワイン

「フェウド・アランチョ ネロ・ダーヴォラ」は、味わい深く、コスパの良い、安定した品質の一本です。 トマト系の煮込み料理や、チーズをたっぷりのせたラザニアとも合い、もちろん、静かな夜にひとりでグラスを傾ける時間にもぴったり。 海外の専門家たちからも高評価を得ており、日常使いからしっかりした食事まで汎用的に活躍します。 味と風味 口に含むと、熟したダークベリーやラズベリーの果実味が広がりながら、後半にかけてほんのりドライハーブのような余韻が続きます。 酸味は控えめで、タンニンはしっかりしています。 飲みごたえ ...

続きを読む

エナジードリンク 今日の一杯

2025/6/30

ZONe ENERGY ABSOLUTE VICTORY 勝 レビュー|今日の一杯 エナジードリンク

ZONe ABSOLUTE VICTORYは2025年1月に発売されたエナジードリンクです。 受験勉強をイメージしたデザインの商品で、学問の神様として知られる菅原道真公を祀る太宰府天満宮に「HYPER ZONe 」を奉納し、受験生の合格を祈願しているそうです。 寒い冬に体を温めるように、成分にジンジャーシロップが配合されており、堅調に生姜の味がします。 カナダドライのジンジャーエールとはまた違う、比較的マイルドな飲みやすい生姜ジュースといった印象です。 ZONeの1本あたりのカフェイン量は75mgとコーヒ ...

続きを読む

  • この記事を書いた人

朝倉卍丸

シングルモルトスコッチなどのお土産を持ってきた人を助けるのが好きです。サービスの分割が重要ですが、まあ昔ながらの方法でやりたいこともありますよね。

よく読まれている記事

条件の0=0は全てが正であるを意味するSQL 1

SQLの条件に0=0のような記述を見かけます。 変わった書き方の条件ですが、これは「全てが正である」事を意味しており、結合条件の場合はCROSS JOINと同じです。 下記の例で言えば、結合するsub ...

DISTINCTを使わないで重複排除を考えるSQL 2

SQLのDISTINCTはEXISTSとかGROUP BYでなんとかする事もできます。 DISTINCTは暗黙的なソートがされますが、何のDBを使うにせよ過去のバージョンならともかく、最近のバージョン ...

RFC 5322に準拠させた正規表現言語別 3

RFC5322で定義されている正規表現を、各言語の正規表現に変化させた形になります。 完全な電子メール正規表現は存在しないので、結局のところ何かの公式基準に従っていたとしても、自分が携わるサービスのル ...

-SQL, SQLServer