
はじめに
こんにちは。Oracle Databaseの検証チームです。
今回は、Oracle Database 26aiの新機能である「マテリアライズド・ビューの同時リフレッシュ」をご紹介いたします。
※本機能は従来の23aiから使用可能です。
今回の執筆者は以下の記事に登場しています!
ORACLE MASTER Silver DBA 2019、 Oracle Cloud Infrastructure 2024 Certified Foundations Associateを取得しました!
過去のOracle Database 26aiの記事はこちら!
一部23aiと表示されています。

マテリアライズド・ビューとは
マテリアライズド・ビューとは、事前に定義されたSELECT結果を表として保持する機能です。
ビューに対し、実テーブルにSELECT結果を保持しているため比較的高速にデータの取得ができます。
また、実テーブルに保持しているデータはある時点のものであるため、最新化する場合は別途リフレッシュが必要となります。
マテリアライズド・ビューの同時リフレッシュとは
従来のマテリアライズド・ビューでは、on commit時のリフレッシュ処理はシリアルでの実行となっており、リフレッシュを行ったセッションが終了するまでその他のリフレッシュはブロックされていました。
Oracle Database 26aiからは、マテリアライズド・ビューを複数のセッションから同時にリフレッシュすることができるようになりました。
また、マテリアライズド・ビューの同時リフレッシュを利用するには条件があり、Oracleのマニュアルでは以下のように紹介されています。
マテリアライズド・ビューのリフレッシュ
■ コミット時のマテリアライズド・ビューの同時リフレッシュが許可される条件次の条件によって、同時リフレッシュを続行できるかどうかが決まります。 ・同時リフレッシュが有効になっている。(有効にできるのは、コミット時のマテリアライズド・ビューのリフレッシュのみです。) ・すべての同時DMLセッションで同じ実表が更新される。 ・異なるリフレッシュ・セッションで更新されたマテリアライズド・ビュー行が重複しない。
検証
※本検証では、Oracle VM VirtualBoxにOracle Database 23ai Free Developer をインストールした環境を使用しています。
準備
本検証用では、以下のテーブルとマテリアライズド・ビューを作成します。
それぞれのマテリアライズド・ビューは共通のディテール表(表1,表2)を使用します。
表1:orders
【サンプルDDL】 CREATE TABLE orders ( id NUMBER(10), created_date DATE, CONSTRAINT orders_pk PRIMARY KEY (id) ); CREATE MATERIALIZED VIEW LOG ON FRUIT_TAB WITH ROWID,PRIMARY KEY; ※差分リフレッシュを行えるようにマテリアライズド・ビューログも必要
| ID | CREATED_DATE |
|---|---|
| 1 | 25 - 08 - xx |
| 2 | xx - xx - xx |
| ・・・ | ・・・ |
表2:order_lines
【サンプルDDL】 CREATE TABLE order_lines ( id NUMBER(10), order_id NUMBER(10), line_qty NUMBER(5), total_value NUMBER(10,2), created_date DATE, CONSTRAINT order_lines_pk PRIMARY KEY (id), CONSTRAINT ol_o_fk FOREIGN KEY (order_id) REFERENCES orders(id) ); CREATE MATERIALIZED VIEW LOG ON order_lines WITH ROWID,PRIMARY KEY, SEQUENCE(order_id, line_qty, total_value) INCLUDING NEW VALUES; ※差分リフレッシュを行えるようにマテリアライズド・ビューログも必要
| ID | ORDER_ID | LINE_QTY | TOTAL_VALUE | CREATED_DATE |
|---|---|---|---|---|
| 1 | 34 | xx | xxx.xx | 25 - 04 - xx |
| 2 | 11 | xx | xxx.xx | xx - xx - xx |
| ・・・ | ・・・ | ・・・ | ・・・ | ・・・ |
マテリアライズド・ビュー1:mv_order_summary_serial(同時リフレッシュ無効)
【サンプルDDL】 CREATE MATERIALIZED VIEW mv_order_summary_serial REFRESH FAST ON COMMIT AS SELECT o.id AS order_id, COUNT(ol.id) AS line_count, SUM(ol.total_value) AS total_value FROM orders o JOIN order_lines ol ON o.id = ol.order_id GROUP BY o.id ;
| ORDER_ID | LINE_COUNT | TOTAL_VALUE |
|---|---|---|
| 1 | 1024 | xxxxxx.xx |
| 2 | 1012 | xxxxxx.xx |
| 3 | 1048 | xxxxxx.xx |
マテリアライズド・ビュー2:mv_order_summary_concurrent(同時リフレッシュ有効)
【サンプルDDL】 CREATE MATERIALIZED VIEW mv_order_summary_concurrent REFRESH FAST ON COMMIT ENABLE CONCURRENT REFRESH AS SELECT o.id AS order_id, COUNT(ol.id) AS line_count, SUM(ol.total_value) AS total_value FROM orders o JOIN order_lines ol ON o.id = ol.order_id GROUP BY o.id ;
| ORDER_ID | LINE_COUNT | TOTAL_VALUE |
|---|---|---|
| 1 | 1024 | xxxxxx.xx |
| 2 | 1012 | xxxxxx.xx |
| 3 | 1048 | xxxxxx.xx |
リフレッシュの情報を確認できるように、リフレッシュ統計収集を有効化しておきましょう。
SQL> EXEC DBMS_MVIEW_STATS.SET_SYSTEM_DEFAULT ('COLLECTION_LEVEL','ADVANCED');
PL/SQLプロシージャが正常に完了しました。
同時リフレッシュの有効化
同時リフレッシュが有効かどうかはALL_MVIEWSの「CONCURRENT_REFRESH_ENABLED」という項目で確認できます。
SQL> SELECT MVIEW_NAME,CONCURRENT_REFRESH_ENABLED from ALL_MVIEWS ; MVIEW_NAME CONCURRENT_REFRESH_ENABLED ____________________________ ___________________ MV_ORDER_SUMMARY_SERIAL N MV_ORDER_SUMMARY_CONCURRENT Y
「MV_ORDER_SUMMARY_SERIAL」のCONCURRENT_REFRESH_ENABLEDの値は「N」となっているため、同時リフレッシュが無効化されている状態です。
この状態だと従来通りシリアル実行のリフレッシュ動作となります。
もう一方の「MV_ORDER_SUMMARY_CONCURRENT」のCONCURRENT_REFRESH_ENABLEDの値は「Y」となっているため、同時リフレッシュが有効化されています。
後から有効化する場合は以下のSQLで有効化できます。
ALTER MATERIALIZED VIEW <マテリアライズド・ビュー名> ENABLE CONCURRENT REFRESH;
リフレッシュの確認
複数のセッションでINSERT,COMMITを行い、どのような差が出るか見てみましょう。
セッション1
SQL> SELECT SYS_CONTEXT('USERENV', 'SESSIONID'); SYS_CONTEXT('USERENV','SESSIONID') _____________________________________ 120039 SQL> INSERT INTO orders 2 SELECT ID + 10000, TRUNC(SYSDATE - DBMS_RANDOM.VALUE(0, 366)) 3* FROM orders WHERE ID <= 10000; 10,000行挿入しました。 SQL> INSERT INTO order_lines 2 SELECT ID + 1000000, TRUNC(DBMS_RANDOM.VALUE(1, 1000)), TRUNC(DBMS_RANDOM.VALUE(1, 20)), 3 ROUND(DBMS_RANDOM.VALUE(1, 1000), 2), TRUNC(SYSDATE - DBMS_RANDOM.VALUE(0, 366)) 4* FROM order_lines WHERE ID <= 1000000; 1,000,000行挿入しました。
セッション2
SQL> SELECT SYS_CONTEXT('USERENV', 'SESSIONID'); SYS_CONTEXT('USERENV','SESSIONID') _____________________________________ 120040 SQL> INSERT INTO orders 2 SELECT ID + 20000, TRUNC(SYSDATE - DBMS_RANDOM.VALUE(0, 366)) 3* FROM orders WHERE ID <= 10000; 10,000行挿入しました。 SQL> INSERT INTO order_lines 2 SELECT ID + 2000000, TRUNC(DBMS_RANDOM.VALUE(1, 1000)), TRUNC(DBMS_RANDOM.VALUE(1, 20)), 3 ROUND(DBMS_RANDOM.VALUE(1, 1000), 2), TRUNC(SYSDATE - DBMS_RANDOM.VALUE(0, 366)) 4* FROM order_lines WHERE ID <= 1000000; 1,000,000行挿入しました。
セッション3
SQL> SELECT SYS_CONTEXT('USERENV', 'SESSIONID'); SYS_CONTEXT('USERENV','SESSIONID') _____________________________________ 120041 SQL> INSERT INTO orders 2 SELECT ID + 30000, TRUNC(SYSDATE - DBMS_RANDOM.VALUE(0, 366)) 3* FROM orders WHERE ID <= 10000; 10,000行挿入しました。 SQL> INSERT INTO order_lines 2 SELECT ID + 3000000, TRUNC(DBMS_RANDOM.VALUE(1, 1000)), TRUNC(DBMS_RANDOM.VALUE(1, 20)), 3 ROUND(DBMS_RANDOM.VALUE(1, 1000), 2), TRUNC(SYSDATE - DBMS_RANDOM.VALUE(0, 366)) 4* FROM order_lines WHERE ID <= 1000000; 1,000,000行挿入しました。
上記それぞれのセッションでCOMMITを発行し、リフレッシュの情報を確認してみます。
パターン1:マテリアライズド・ビューごとに確認
それぞれのマテリアライズド・ビューごとにリフレッシュの動作を確認したところ以下のようになりました。
【同時リフレッシュOFF】 SQL> SELECT 2 MV_NAME, 3 REFRESH_ID, 4 REFRESH_METHOD, 5 START_TIME, 6 END_TIME, 7 (END_TIME - START_TIME) AS ELAPSED_SECONDS 8 FROM 9 DBA_MVREF_STATS 10 ORDER BY 11* START_TIME DESC; MV_NAME REFRESH_ID REFRESH_METHOD START_TIME END_TIME ELAPSED_SECONDS __________________________ _____________ _________________ ______________________________ ______________________________ ______________________ MV_ORDER_SUMMARY_SERIAL 26 FAST 25-10-23 11:15:02.000000000 25-10-23 11:15:15.000000000 +00 00:00:13.000000 MV_ORDER_SUMMARY_SERIAL 25 FAST 25-10-23 11:08:35.000000000 25-10-23 11:09:15.000000000 +00 00:00:40.000000 MV_ORDER_SUMMARY_SERIAL 24 FAST 25-10-23 11:03:29.000000000 25-10-23 11:04:14.000000000 +00 00:00:45.000000
【同時リフレッシュON】 SQL> SELECT 2 MV_NAME, 3 REFRESH_ID, 4 REFRESH_METHOD, 5 START_TIME, 6 END_TIME, 7 (END_TIME - START_TIME) AS ELAPSED_SECONDS 8 FROM 9 DBA_MVREF_STATS 10 ORDER BY 11* START_TIME DESC; MV_NAME REFRESH_ID REFRESH_METHOD START_TIME END_TIME ELAPSED_SECONDS ______________________________ _____________ _________________ ______________________________ ______________________________ ______________________ MV_ORDER_SUMMARY_CONCURRENT 29 FAST 25-10-23 11:33:30.000000000 25-10-23 11:44:11.000000000 +00 00:10:41.000000 MV_ORDER_SUMMARY_CONCURRENT 28 FAST 25-10-23 11:33:30.000000000 25-10-23 11:39:01.000000000 +00 00:05:31.000000 MV_ORDER_SUMMARY_CONCURRENT 27 FAST 25-10-23 11:33:30.000000000 25-10-23 11:34:20.000000000 +00 00:00:50.000000
START_TIMEとEND_TIMEの列を見てみると、同時リフレッシュがOFFの場合はシリアル実行されているのに対し、同時リフレッシュがONの場合は同じタイミングで開始されていることがわかります。
また、全体の実行時間に関しては同時リフレッシュOFFが12分弱、同時リフレッシュONが11分弱となっており、同時リフレッシュONの方が少し早いという結果になりました。
パターン2:同時に確認
同じディテール表に対して両パターンのマテリアライズド・ビューを作成した場合、以下のようになりました。
SQL> SELECT 2 MV_NAME, 3 REFRESH_ID, 4 REFRESH_METHOD, 5 START_TIME, 6 END_TIME, 7 (END_TIME - START_TIME) AS ELAPSED_SECONDS 8 FROM 9 DBA_MVREF_STATS 10 ORDER BY 11* START_TIME DESC; MV_NAME REFRESH_ID REFRESH_METHOD START_TIME END_TIME ELAPSED_SECONDS ______________________________ _____________ _________________ ______________________________ ______________________________ ______________________ MV_ORDER_SUMMARY_SERIAL 23 FAST 25-10-23 08:55:15.000000000 25-10-23 08:55:30.000000000 +00 00:00:15.000000 MV_ORDER_SUMMARY_CONCURRENT 23 FAST 25-10-23 08:55:15.000000000 25-10-23 08:55:38.000000000 +00 00:00:23.000000 MV_ORDER_SUMMARY_SERIAL 22 FAST 25-10-23 08:49:26.000000000 25-10-23 08:49:51.000000000 +00 00:00:25.000000 MV_ORDER_SUMMARY_CONCURRENT 22 FAST 25-10-23 08:49:26.000000000 25-10-23 08:50:10.000000000 +00 00:00:44.000000 MV_ORDER_SUMMARY_SERIAL 21 FAST 25-10-23 08:47:31.000000000 25-10-23 08:47:57.000000000 +00 00:00:26.000000 MV_ORDER_SUMMARY_CONCURRENT 21 FAST 25-10-23 08:47:31.000000000 25-10-23 08:48:06.000000000 +00 00:00:35.000000 6行が選択されました。
START_TIMEの列を見ると、同時リフレッシュが有効な場合でもシリアル実行されていることがわかります。
また、同じ実行タイミングのリフレッシュを比較した場合、同時リフレッシュが有効になっている方が処理に時間がかかっているようです。
同時リフレッシュがONの場合でもシリアル実行となってしまう場合、従来のリフレッシュに戻したほうがよいかもしれませんね。
おわりに
今回はマテリアライズド・ビューの同時リフレッシュについて紹介してみました。
本機能はすべての場合に有効というわけではないですが、選択肢の幅が広がることでより便利になったと思います。
on commitを使用したマテリアライズド・ビューをお使いの環境で、処理速度が気になっている場合、26aiにて本機能を検討してみてはいかがでしょうか。
最後までお読みいただきありがとうございました。
Oracle Databaseに関してお困りごとがあれば、ぜひ当社へご相談ください。

投稿者プロフィール

-
DBひとりでできるもんを盛り上げるべく、技術チームが立ち上がり早8年。ひとりでできるもんと言いつつ、技術者が読んでプッとなるような、極めてピンポイントでマニアックな技術ネタを執筆しています!
最新技術情報や資格情報をチェックしたいアナタ!毎日遊びに来てください。きっとお役に立てます。
最新の投稿
23ai2025年12月3日【Oracle 26ai 新機能】マテリアライズド・ビューの同時リフレッシュを使ってみた
23ai2025年12月3日【Oracle Database】JSONリレーショナル二面性ビューを使ってみた
Dbvisit Standby2025年11月10日【Dbvisit Standby】SQL ServerでDRを構成してみました!
Dbvisit Standby2025年11月7日【Dbvisit Standby】最新バージョン(Ver.12.2.0)がリリースされました!

