「複雑な集計クエリが遅い」「毎回同じ重いJOINを実行している」——そんなときに使えるのがマテリアライズドビュー(MV)です。集計結果を物理的に保存しておき、高速にアクセスできるOracle固有の機能を解説します。
目次
1. マテリアライズドビューとは(通常ビューとの違い) {#about}
| 比較項目 | 通常ビュー(VIEW) | マテリアライズドビュー(MV) |
|---|---|---|
| データの保存 | 保存しない(SQLを保存するだけ) | 物理的に結果を保存 |
| アクセス速度 | 毎回元テーブルを参照(遅い場合あり) | 保存済み結果を読むだけ(高速) |
| データの新鮮さ | 常に最新 | リフレッシュするまで古い場合がある |
| 用途 | 権限管理・複雑なSQLの簡略化 | 集計高速化・DWH・レポート |
マテリアライズドビューが効果的なケース:
- 毎時・毎日集計する大量データのレポート
- 複数テーブルのJOIN結果を繰り返し使う
- リモートDBのデータをローカルにキャッシュする(DBリンク経由)
2. マテリアライズドビューの作成 {#create-mv}
シンプルな集計MVを作成
-- 部門ごとの給与集計をMVとして保存
CREATE MATERIALIZED VIEW MV_DEPT_SALARY
AS
SELECT
department_id,
COUNT(*) AS headcount,
AVG(salary) AS avg_salary,
MAX(salary) AS max_salary,
SUM(salary) AS total_salary
FROM employees
GROUP BY department_id;リフレッシュ設定付きで作成(推奨)
CREATE MATERIALIZED VIEW MV_DEPT_SALARY
REFRESH FAST -- 差分更新(FAST/COMPLETE/FORCE/NEVER)
ON DEMAND -- 手動でリフレッシュ(ON COMMIT/ON DEMANDから選択)
WITH QUERY REWRITE -- クエリリライトを有効化
AS
SELECT
department_id,
COUNT(*) AS headcount,
SUM(salary) AS total_salary
FROM employees
GROUP BY department_id;自動リフレッシュ(スケジュール付き)
CREATE MATERIALIZED VIEW MV_MONTHLY_SALES
REFRESH COMPLETE
START WITH SYSDATE
NEXT TRUNC(SYSDATE + 1) -- 翌日0時から毎日更新
AS
SELECT
TRUNC(sale_date, 'MM') AS sale_month,
region,
SUM(amount) AS total_amount
FROM sales
GROUP BY TRUNC(sale_date, 'MM'), region;3. リフレッシュ(更新)の方法と設定 {#refresh}
リフレッシュの種類
| 種類 | 内容 | 速度 | 条件 |
|---|---|---|---|
| COMPLETE | MVを全削除して再作成 | 遅い | いつでも使用可能 |
| FAST | 変更分のみ更新(差分更新) | 速い | マテリアライズドビューログが必要 |
| FORCE | FASTが可能ならFAST、不可ならCOMPLETE | – | 自動判断 |
| NEVER | 自動リフレッシュしない | – | 手動のみ |
FAST リフレッシュに必要なマテリアライズドビューログの作成
-- 元テーブル(employees)にMVログを作成(FASTリフレッシュの前提)
CREATE MATERIALIZED VIEW LOG ON employees
WITH ROWID, SEQUENCE (employee_id, department_id, salary)
INCLUDING NEW VALUES;手動でリフレッシュする
-- 単一MVをCOMPLETEリフレッシュ
BEGIN
DBMS_MVIEW.REFRESH('MV_DEPT_SALARY', 'C'); -- C=COMPLETE, F=FAST
END;
/
-- 複数MVを一括リフレッシュ
BEGIN
DBMS_MVIEW.REFRESH_ALL_MVIEWS(out_failures => 0);
END;
/
-- 依存関係順にリフレッシュ
BEGIN
DBMS_MVIEW.REFRESH_DEPENDENT(list => 'EMPLOYEES');
END;
/4. クエリリライト(自動高速化) {#query-rewrite}
クエリリライトとは、元テーブルへのクエリを自動的にMVへのクエリに書き換えてくれる機能です。
-- MVを作成するときにWITH QUERY REWRITEを指定
CREATE MATERIALIZED VIEW MV_DEPT_SALARY
ENABLE QUERY REWRITE
AS
SELECT department_id, SUM(salary) AS total
FROM employees
GROUP BY department_id;-- 元テーブルへのクエリ(オプティマイザが自動的にMVを使う)
SELECT department_id, SUM(salary)
FROM employees
GROUP BY department_id;
-- → 内部的に MV_DEPT_SALARY から読む(高速)クエリリライトが機能しているか確認:
EXPLAIN PLAN FOR
SELECT department_id, SUM(salary)
FROM employees
GROUP BY department_id;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
-- 実行計画に MV_DEPT_SALARY が表示されればリライト成功5. マテリアライズドビューの確認と管理 {#check-mv}
一覧の確認
SELECT
MVIEW_NAME,
REFRESH_METHOD,
REFRESH_MODE,
LAST_REFRESH_TYPE,
LAST_REFRESH_DATE,
COMPILE_STATE
FROM USER_MVIEWS
ORDER BY MVIEW_NAME;COMPILE_STATEの値:
| 値 | 意味 |
|---|---|
| VALID | 正常 |
| NEEDS_COMPILE | 元テーブルの変更でMVが無効化(コンパイルが必要) |
| ERROR | エラーあり |
MVを再コンパイル
-- 元テーブルのDDL変更後にMVが無効になった場合
ALTER MATERIALIZED VIEW MV_DEPT_SALARY COMPILE;MVの削除
DROP MATERIALIZED VIEW MV_DEPT_SALARY;6. よくあるエラーと対処 {#errors}
ORA-23413:テーブルにマテリアライズドビューログがない
ORA-23413: "SCOTT"."EMPLOYEES"にマテリアライズド・ビュー・ログがありませんFASTリフレッシュを使う場合はMVログが必要です。
CREATE MATERIALIZED VIEW LOG ON employees
WITH ROWID, SEQUENCE (department_id, salary)
INCLUDING NEW VALUES;ORA-12054:ON COMMITリフレッシュはサポートされない
集計(GROUP BY・DISTINCT)を含むMVにはON COMMITは使えません。ON DEMANDに変更します。
MVのデータが古い
手動リフレッシュが必要な場合、または自動リフレッシュのスケジュールを確認します。
-- 最終リフレッシュ日時を確認
SELECT MVIEW_NAME, LAST_REFRESH_DATE FROM USER_MVIEWS;
-- 手動で更新
EXEC DBMS_MVIEW.REFRESH('MV_DEPT_SALARY', 'C');7. まとめ:MV活用チェックリスト {#summary}
設計時
□ FAST リフレッシュを使う場合は元テーブルに MV LOG を作成
□ ON COMMIT は単純な集計MVに限定(制約が多い)
□ リフレッシュ頻度はデータの鮮度要件に合わせて設定
運用時
□ USER_MVIEWS で COMPILE_STATE が VALID か定期確認
□ LAST_REFRESH_DATE で更新が滞っていないか確認
□ 元テーブルのDDL変更後は ALTER MATERIALIZED VIEW ... COMPILE で再コンパイル
パフォーマンス
□ ENABLE QUERY REWRITE を指定してクエリリライトを有効化
□ EXPLAIN PLAN でMVが使われているか確認
□ リフレッシュ処理中はMVが書き込みロックされるため、時間帯に注意関連記事:









コメント