Oracleの統計情報収集は基本中の基本ですが、現場では「収集したら逆に遅くなった」「本番と検証で同じ実行計画にしたい」といった場面がよくあります。
この記事では、DBMS_STATS の応用プロシージャを使った以下の操作を解説します。
- 統計情報のロック(固定化)
- 統計情報の削除
- 統計情報のバージョン復元(古い統計情報に戻す)
- 統計情報の環境間移行(本番→検証)
統計情報のロック(固定化)
なぜロックが必要なのか
夜間の自動統計収集で実行計画が変わって、翌朝から急にSQLが遅くなる──これは現場でよくある「あるある」です。
特定のテーブルの統計情報を固定化しておくと、自動収集・手動収集の対象から外れ、実行計画が安定します。
テーブルの統計情報をロックする
sql
BEGIN
DBMS_STATS.LOCK_TABLE_STATS(
OWNNAME => 'オーナー名'
,TABNAME => 'テーブル名'
);
END;
/ロックされているか確認する
sql
SELECT TABLE_NAME, STATTYPE_LOCKED
FROM USER_TAB_STATISTICS
WHERE TABLE_NAME = 'テーブル名'
;STATTYPE_LOCKED が ALL になっていればロックされています。
スキーマ全体をロックする
sql
BEGIN
DBMS_STATS.LOCK_SCHEMA_STATS(
OWNNAME => 'オーナー名'
);
END;
/ロックを解除する
sql
BEGIN
DBMS_STATS.UNLOCK_TABLE_STATS(
OWNNAME => 'オーナー名'
,TABNAME => 'テーブル名'
);
END;
/統計情報の削除
テーブルやインデックスの統計情報を削除(クリア)します。削除後はOracleが動的サンプリングを使用します。
注意: 統計情報を削除すると、オプティマイザがSQLの最初の実行時に動的サンプリングを行うため、初回実行が遅くなることがあります。
テーブルの統計情報を削除する
sql
BEGIN
DBMS_STATS.DELETE_TABLE_STATS(
OWNNAME => 'オーナー名'
,TABNAME => 'テーブル名'
);
END;
/インデックスの統計情報を削除する
sql
BEGIN
DBMS_STATS.DELETE_INDEX_STATS(
OWNNAME => 'オーナー名'
,INDNAME => 'インデックス名'
);
END;
/スキーマ全体の統計情報を削除する
sql
BEGIN
DBMS_STATS.DELETE_SCHEMA_STATS(
OWNNAME => 'オーナー名'
);
END;
/統計情報のバージョン復元(以前の統計情報に戻す)
Oracle 10g以降、統計情報は変更前の値が自動的に保存されています(デフォルト保存期間:31日間)。統計収集後に実行計画が悪化した場合、前の統計情報に戻すことができます。
保存されている統計情報の履歴を確認する
sql
SELECT STATS_UPDATE_TIME
FROM DBA_OPTSTAT_OPERATIONS
WHERE OPERATION IN ('gather_table_stats', 'gather_schema_stats')
ORDER BY STATS_UPDATE_TIME DESC
;特定の時刻の統計情報に戻す
sql
BEGIN
DBMS_STATS.RESTORE_TABLE_STATS(
OWNNAME => 'オーナー名'
,TABNAME => 'テーブル名'
,AS_OF_TIMESTAMP => TO_TIMESTAMP('2026-04-01 22:00:00', 'YYYY-MM-DD HH24:MI:SS')
);
END;
/スキーマ全体を特定時刻に戻す
sql
BEGIN
DBMS_STATS.RESTORE_SCHEMA_STATS(
OWNNAME => 'オーナー名'
,AS_OF_TIMESTAMP => TO_TIMESTAMP('2026-04-01 22:00:00', 'YYYY-MM-DD HH24:MI:SS')
);
END;
/統計情報の保存期間を変更する(デフォルト31日)
sql
-- 60日間に変更する例
BEGIN
DBMS_STATS.ALTER_STATS_HISTORY_RETENTION(60);
END;
/
-- 現在の保存期間を確認する
SELECT DBMS_STATS.GET_STATS_HISTORY_RETENTION FROM DUAL;統計情報の環境間移行(本番→検証への移行)
本番環境の統計情報を検証環境にコピーすることで、検証環境でも本番と同じ実行計画を再現できます。
手順の概要
本番環境 ──エクスポート──► stattab(中間テーブル)──インポート──► 検証環境手順1:中間テーブル(stattab)を作成する
本番・検証の両環境に統計情報格納用のテーブルを作成します。
sql
BEGIN
DBMS_STATS.CREATE_STAT_TABLE(
OWNNAME => 'オーナー名'
,STATTAB => 'STATS_WORK' -- 任意のテーブル名
);
END;
/手順2:本番環境の統計情報をstattabにエクスポートする
sql
BEGIN
DBMS_STATS.EXPORT_TABLE_STATS(
OWNNAME => 'オーナー名'
,TABNAME => 'テーブル名'
,STATTAB => 'STATS_WORK'
);
END;
/手順3:stattabを検証環境に転送する
Data PumpやDB Linkなどでstattabのデータを検証環境にコピーします。
sql
-- DB Linkを使う場合の例(本番→検証方向に接続できる場合)
INSERT INTO STATS_WORK
SELECT * FROM STATS_WORK@本番のDBリンク名;
COMMIT;手順4:検証環境にインポートする
sql
BEGIN
DBMS_STATS.IMPORT_TABLE_STATS(
OWNNAME => 'オーナー名'
,TABNAME => 'テーブル名'
,STATTAB => 'STATS_WORK'
);
END;
/主要プロシージャ一覧まとめ
| プロシージャ | 機能 |
|---|---|
LOCK_TABLE_STATS | テーブル統計情報をロック(固定化) |
LOCK_SCHEMA_STATS | スキーマ全体をロック |
UNLOCK_TABLE_STATS | テーブル統計情報のロック解除 |
DELETE_TABLE_STATS | テーブル統計情報を削除 |
DELETE_SCHEMA_STATS | スキーマ全体の統計情報を削除 |
RESTORE_TABLE_STATS | 特定時刻の統計情報に復元 |
RESTORE_SCHEMA_STATS | スキーマ全体を特定時刻に復元 |
EXPORT_TABLE_STATS | 統計情報をstattabにエクスポート |
IMPORT_TABLE_STATS | stattabから統計情報をインポート |
CREATE_STAT_TABLE | stattab(中間テーブル)を作成 |
よくある質問(FAQ)
Q. 統計情報をロックしても手動で更新できますか?
FORCE => TRUE オプションを指定することでロック中でも強制更新できます。
sql
DBMS_STATS.GATHER_TABLE_STATS(OWNNAME=>'..', TABNAME=>'..', FORCE=>TRUE);Q. 統計情報を復元できる期間はどれくらいですか?
デフォルトは31日間(設定変更可能)。この期間内であれば任意の時刻の統計情報に戻せます。
Q. 検証環境に本番の統計情報を入れる意味はありますか?
あります。本番と検証でデータ量が違うと、異なる実行計画が使われてしまいます。本番統計情報をインポートすることで、検証環境でも本番に近い実行計画での動作確認が可能になります。
まとめ
- 夜間の自動統計収集で実行計画が変わる → LOCK_TABLE_STATS で固定化
- 統計収集後に遅くなった → RESTORE_TABLE_STATS で以前の状態に復元
- 本番と同じ動作を検証環境で再現したい → EXPORT/IMPORT_TABLE_STATS で移行
統計情報を制御する知識は、Oracleのパフォーマンス維持に欠かせません。基本の収集(GATHER)だけでなく、ロック・削除・復元もマスターして、より安定したOracle運用を実現してください。





コメント