SQL ServerでREBUILDとREORGANIZEの使い分けに迷ったら、まず結論です。日中も更新を止めにくい通常運用では、常にオンラインで葉レベルを整えるREORGANIZEを第一候補にし、インデックス全体を作り直したい、無効化したインデックスを戻したい、fill factorを変えたい、ページ密度の立て直しまで必要ならREBUILDを選ぶのが基本です。ただし、Microsoftは固定の断片化率しきい値だけで判断しないよう勧めています。実際には、断片化率だけでなく、ページ密度、統計の鮮度、どんなクエリがそのインデックスを読んでいるかまで見たほうが、無駄なメンテナンスを避けやすくなります。(Microsoft Learn)
この記事では、SQL ServerのREBUILDとREORGANIZEの仕様差を整理したうえで、実務での判断基準、よくある勘違い、すぐ使える確認クエリ、例外ケースまでまとめます。読み終えるころには、「今このインデックスに本当に必要なのはどちらか」を自分で判断しやすくなります。(Microsoft Learn)
SQL ServerでREBUILDとREORGANIZEをどう使い分けるか
以下は、通常の行ストア(B-tree)インデックスを前提に、公式仕様を実務向けに整理した比較です。列ストアとヒープは後半で別扱いします。(Microsoft Learn)
| 観点 | REORGANIZE | REBUILD |
|---|---|---|
| 何をするか | リーフレベルを論理順に並べ直し、ページを圧縮する | インデックスを削除して再作成する |
| 実行方式 | 常にオンライン | オフラインまたはオンライン |
| 統計への影響 | インデックス統計は更新されない | 行ストアでは通常インデックス統計が更新される |
| 向く場面 | 業務継続優先、軽量に整えたい、LOB圧縮もしたい | 全面刷新、fill factor変更、disabled index復帰、パーティション単位の再構築 |
| 代表的な注意点 | ALLOW_PAGE_LOCKS = OFFやdisabled indexでは使えない。明示トランザクションでは挙動に注意 | ディスク・CPU・I/O負荷が大きい。オンラインでも開始/終了時に短いロックが必要。エディションやインデックス種別の制約がある |
比較表だけ覚えるなら、止めたくないならREORGANIZE、作り直す必要があるならREBUILDです。ただし、この一行だけで運用すると失敗しやすいので、次から判断の軸を具体化します。(Microsoft Learn)
断片化率だけで決めると失敗しやすい理由
よくある「5〜30%ならREORGANIZE、30%以上ならREBUILD」のようなルールは、出発点にはなっても絶対基準ではありません。Microsoftは、インデックスメンテナンスは固定の断片化率やページ密度のしきい値だけで決めるべきではないと明言しており、Query Storeなどで実際のクエリ性能を測ることを勧めています。また、多くのワークロードでは、断片化を減らすよりページ密度を上げるほうが効果が大きいとされています。(Microsoft Learn)
特に見落としやすいのが、断片化は「そのインデックスが大きなスキャンに使われるとき」に効きやすいという点です。Microsoftは、断片化だけでは再構成・再構築の十分条件にならず、大きなスキャンが発生しないワークロードでは、断片化除去の効果は出ないと説明しています。実務では、レポート系や日付範囲検索で多くのページを読むインデックスを優先し、単発のシーク中心のインデックスは後回しにするほうが現実的です。(Microsoft Learn)
もう一つ重要なのが統計です。行ストアではREBUILDによって通常インデックス統計が更新されますが、REORGANIZEでは統計が更新されません。しかもMicrosoftは、REBUILD後に速くなるケースの多くが、断片化解消そのものではなく、統計改善の副作用である可能性を指摘しています。大量更新や一括取込の直後にプランが崩れたなら、いきなりREBUILDする前にUPDATE STATISTICSを試したほうが、同じ効果をより低コストで得られることがあります。(Microsoft Learn)
迷ったときは、次の表を最初の判断材料にすると整理しやすくなります。これは公式仕様と実務運用を踏まえた「着手順」の目安です。(Microsoft Learn)
| まず見えやすい症状 | 先に疑うべきもの | 先に打つ手 |
|---|---|---|
| 大量更新や一括取込の直後に遅くなった | 統計の劣化 | UPDATE STATISTICS |
| 日中も更新が止められない | 断片化・ページ密度 | REORGANIZE |
| fill factor変更、disabled index復旧、物理構造の作り直しが必要 | インデックス構造そのもの | REBUILD |
| 一部パーティションだけ重い | ホットパーティションの偏り | パーティション単位のREBUILD / REORGANIZE |
REORGANIZEが向くケース
REORGANIZEは、業務を止めずにインデックスを整えたいときの第一候補です。公式ドキュメントでも、REBUILDを使う特別な理由がない限り、より軽量なメンテナンス方法として扱われています。行ストアではリーフレベルのページを論理順に並べ直し、既存のfill factorを基準にページを圧縮します。(Microsoft Learn)
REORGANIZEを選びやすいパターン
- 24時間稼働のOLTPで、長いブロッキングを避けたい
- まずは低コストでページの並びとページ密度を整えたい
varchar(max)やxmlなどのLOB列を含むテーブルで、LOBページの圧縮もしたい- 大きなインデックスを少しずつ進めたい
REORGANIZEは常にオンラインで、途中中断しても完了済みの作業を失わずに再開しやすいのが強みです。LOBデータ型を含む行ストアでは、LOB_COMPACTIONでLOBページの圧縮も行えます。(Microsoft Learn)
逆に、fill factorを変更して今後のページ分割に備えたい、あるいはページを作り直して空き領域を新たに持たせたい用途にはREORGANIZEは向きません。REORGANIZEは既存fill factorに基づいて圧縮するだけで、より低いfill factor用の空き領域を新規に作る動きはしないからです。fill factorの変更を反映したいならREBUILDが必要です。(Microsoft Learn)
また、REORGANIZEは万能ではありません。disabled indexには使えず、ALLOW_PAGE_LOCKS = OFFでも使えません。さらに、明示トランザクションの中で実行するとロッキングが重くなりやすく、ロールバックしてもREORGANIZEの処理自体は巻き戻りません。この挙動は運用事故につながりやすいので要注意です。(Microsoft Learn)
行ストアで業務継続を優先するなら、まずは次のような形で十分です。LOB列があるテーブルでは、既定値はONですが、意図を明確にするため明示しておくとレビューしやすくなります。(Microsoft Learn)
ALTER INDEX IX_Orders_OrderDate
ON Sales.Orders
REORGANIZE WITH (LOB_COMPACTION = ON);
実行後にプラン改善が弱い場合は、REORGANIZEだけでは統計が変わらない点を疑ってください。必要に応じてUPDATE STATISTICSを追加するほうが筋が良いケースは少なくありません。(Microsoft Learn)
REBUILDが向くケース
REBUILDは、インデックスを削除して再作成する方法です。行ストアでは全レベルの断片化を解消し、指定または既存のfill factorに基づいてページを詰め直します。さらに通常はインデックス統計も更新されるため、物理構造と統計の両方をまとめて立て直したいときに強い手段です。(Microsoft Learn)
REBUILDを選ぶべき具体例
DISABLEしたインデックスを有効化したい- fill factorを変更したい
- 大規模
DELETEやUPDATEの後で、ページ密度まで大きく崩れた - 問題のあるパーティションだけ集中的に立て直したい
REORGANIZEと統計更新を試しても改善しない
特に、disabled indexを戻せるのはREBUILDです。また、パーティションテーブルではPARTITION = nで対象を絞れるため、テーブル全体へ機械的にALLをかける前に、まず問題のあるパーティションだけに限定したほうが安全です。(Microsoft Learn)
ただし、fill factorを下げる判断自体は慎重に行うべきです。Microsoftは、ページ分割が多い一部のインデックスを除き、fill factorを100または0以外に設定することを推奨していません。低いfill factorはページ密度を下げ、結果としてI/Oやメモリ消費を増やすからです。非連続GUIDが先頭キーにある更新頻度の高いインデックスなど、本当にページ分割が多い対象だけに絞るのが無難です。(Microsoft Learn)
ONLINE = ONを使えばテーブルは原則アクセス可能ですが、完全な無停止ではありません。開始時と終了時には短時間のSまたはSch-Mロックが必要で、これがスループット低下やタイムアウトの原因になることがあります。ブロッキングを抑えたいならWAIT_AT_LOW_PRIORITYの併用が有効です。ただし、オンライン操作が使えるかどうかはエディション依存です。さらに、再構築中はインデックスのコピーを保持できるだけの領域も必要です。(Microsoft Learn)
長時間の再構築ではRESUMABLE = ONも便利です。オンライン再構築を途中で一時停止・再開できますが、ALTER INDEX REBUILD ALL、filtered index、columnstore index、disabled indexなどでは使えない制約があります。加えて、パーティションインデックスや再開可能な再構築では、統計が常に全行スキャンになるとは限りません。REBUILD = FULLSCAN相当と決め打ちしないほうが安全です。(Microsoft Learn)
メンテナンス窓が限られる環境では、まずは対象を絞ったREBUILDから始めるのが安全です。(Microsoft Learn)
ALTER INDEX IX_FactSales_OrderDate
ON dbo.FactSales
REBUILD PARTITION = 12
WITH (
ONLINE = ON (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 10 MINUTES, ABORT_AFTER_WAIT = SELF)),
MAXDOP = 4
);
エディションやインデックス種別の制約でオンライン再構築が使えない環境では、オフライン実行前提でメンテナンス窓を確保し、対象をさらに絞るのが現実的です。(Microsoft Learn)
REBUILDする前にUPDATE STATISTICSを試すべき場面
性能悪化の原因が統計にあるなら、インデックスを触らずにUPDATE STATISTICSで十分なことがあります。Microsoftは、REBUILDの効果を断片化解消と誤認しやすいこと、実際には統計更新で同様の改善をより低コストで得られる場合があることを示しています。大量更新、一括取込、分布の偏りが大きい列、最近のデータに偏った検索などでは、まず統計更新から試すほうが合理的です。(Microsoft Learn)
なお、FULLSCANは常に必要ではありません。Microsoftは、ほとんどのワークロードでは既定のサンプリングで十分であり、分布の偏りに敏感な一部のケースだけサンプル率引き上げやFULLSCANが必要だと説明しています。毎回フルスキャンで統計更新する運用は、かえって重くなりがちです。(Microsoft Learn)
-- まずは既定サンプリングで更新
UPDATE STATISTICS Sales.Orders;
-- 分布の偏りが強く、既定サンプリングで足りないと判断したときだけ
UPDATE STATISTICS Sales.Orders (IX_Orders_OrderDate) WITH FULLSCAN;
「遅いからとりあえずREBUILD」ではなく、「統計か、物理断片化か」を切り分けてから手を打つほうが、運用コストも障害リスクも下げやすくなります。(Microsoft Learn)
判断に使える確認クエリと手順
候補抽出には、まずsys.dm_db_index_physical_statsを使います。MicrosoftもSAMPLEDで素早く実用的な結果を取り、必要ならDETAILEDで精査する流れを示しています。SAMPLEDは近似値で、10,000ページ未満ではDETAILEDが使われます。(Microsoft Learn)
SELECT
OBJECT_SCHEMA_NAME(ips.object_id) AS schema_name,
OBJECT_NAME(ips.object_id) AS object_name,
i.name AS index_name,
i.type_desc,
ips.avg_fragmentation_in_percent,
ips.avg_page_space_used_in_percent,
ips.page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), DEFAULT, DEFAULT, DEFAULT, 'SAMPLED') AS ips
INNER JOIN sys.indexes AS i
ON ips.object_id = i.object_id
AND ips.index_id = i.index_id
WHERE i.index_id > 0
AND ips.alloc_unit_type_desc = 'IN_ROW_DATA'
AND ips.index_level = 0
ORDER BY ips.page_count DESC,
ips.avg_fragmentation_in_percent DESC;
実務では、次の順番で判断すると迷いにくくなります。(Microsoft Learn)
- まず
SAMPLEDで候補抽出し、page_countが大きいものから見る - Query Storeや実行プランで、大きなスキャンを伴うクエリと結びついているか確認する
- 直近の大量更新・一括取込・分布変化があるなら、先に
UPDATE STATISTICSを試す - 業務継続を優先するなら
REORGANIZE、構造を作り直す必要があるならREBUILDを選ぶ - 効果があった対象だけを定期運用に組み込み、全インデックス一律メンテは避ける
この順番にしておくと、「断片化率だけ高かった小さなインデックスに時間を使う」「本当は統計更新で済むのに重いREBUILDを毎回流す」といったムダを減らせます。(Microsoft Learn)
運用で失敗しやすいポイント
よくある失敗を先に潰しておくと、REBUILDとREORGANIZEの運用はかなり安定します。(Microsoft Learn)
| 失敗しやすい判断 | 何が問題か | 実務での対処 |
|---|---|---|
断片化率だけ見て毎晩ALTER INDEX ALL ... REBUILDを流す | 不要なCPU・I/O・ログ消費になる。改善が統計更新の副作用かもしれない | Query Storeで効果のある対象だけに絞る |
ONLINE = ONなら無停止だと思い込む | 開始時と終了時に短いロックが必要 | WAIT_AT_LOW_PRIORITYとメンテ窓を併用する |
REORGANIZE後に統計も新しくなると思い込む | REORGANIZEは統計を更新しない | 必要ならUPDATE STATISTICSを別で実行する |
| fill factorを全部80などに下げる | ページ密度が下がり、I/Oやメモリ使用量が増える | ページ分割が多い特定インデックスだけ調整する |
REORGANIZEを明示トランザクションで囲む | ロッキングが重くなり、ロールバックしても処理は巻き戻らない | 単独実行を基本にする |
disabled indexやALLOW_PAGE_LOCKS = OFFのままREORGANIZEする | 仕様上そのままでは実行できない | 状態や設定を直すか、REBUILDへ切り替える |
ALTER INDEX ALL ... REBUILD WITH (ONLINE = ON)を万能視する | XML・spatial・columnstoreなどの混在で失敗しうる | テーブル上のインデックス種別を確認して対象を分ける |
例外として押さえておきたいケース
ヒープはこの二択の外側にある
ヒープでは、ALTER INDEX ... REBUILDでALLを指定してもヒープ自体には効果がなく、関連する非クラスター化インデックスが再構築されるだけです。ヒープそのものを再構築したいなら、ALTER TABLE ... REBUILDを使うか、一時的にクラスター化インデックスを作成して削除する方法を取ります。更新が多いヒープではforwarded recordも問題になりやすいので、インデックス断片化とは別の観点で見る必要があります。(Microsoft Learn)
列ストアは行ストアと判断軸が違う
列ストアではREORGANIZEの役割がかなり違います。SQL Server 2016以降のREORGANIZEは、削除済み行の物理削除やrowgroupの結合をオンラインで行えます。さらにSQL Server 2019以降は、tuple-moverを支援するバックグラウンドマージにより、手動のREORGANIZEが必要になる場面自体が減っています。行ストアの感覚で毎回REBUILDを選ばないよう注意が必要です。(Microsoft Learn)
古いDBCCコマンドは置き換える
古いメンテナンススクリプトにDBCC DBREINDEXやDBCC INDEXDEFRAGが残っているなら、見直し対象です。Microsoftは、前者をALTER INDEX ... REBUILD、後者をALTER INDEX ... REORGANIZEへ書き換えるよう案内しています。断片化確認もDBCC SHOWCONTIGではなくsys.dm_db_index_physical_statsを使います。(Microsoft Learn)
まとめ
REORGANIZEは軽く、止めずに整える手段、REBUILDは作り直して立て直す手段です。ですが、運用で本当に効くかは断片化率の数字だけでは決まりません。まずsys.dm_db_index_physical_statsでavg_fragmentation_in_percent、avg_page_space_used_in_percent、page_countを見て、Query Storeで影響の大きいクエリを確認し、統計が怪しければUPDATE STATISTICSを先に試す。そのうえで、止めたくないならREORGANIZE、作り直しが必要なら対象を絞ってREBUILD、という順で進めるのが失敗しにくい進め方です。(Microsoft Learn)
今日から始めるなら、次の3手で十分です。(Microsoft Learn)
SAMPLEDで候補インデックスを抽出する- 影響の大きいクエリと結びつく対象だけに絞る
UPDATE STATISTICS→REORGANIZE / REBUILDの順で前後比較する

コメント