マテリアライズドビューを使用してクエリを高速化する場合、ベーステーブルに対するクエリ実行時に、システムは自動的に既存のマテリアライズドビューを使用したクエリにリライトします。この方法の原理は、クエリステートメントとマテリアライズドビューの定義を照合し、一致するマテリアライズドビューが見つかった場合には、自動的にそのマテリアライズドビューを使用したクエリにリライトすることで、クエリのパフォーマンスと効率を大幅に向上させることです。
マテリアライズドビューによるクエリのリライトの制限
マテリアライズドビューは以下の要件を満たしている必要があります:
- マテリアライズドビューを作成する際に、
ENABLE QUERY REWRITE句を指定する必要があります。 - マテリアライズドビューには
SELECT、JOIN、WHERE、GROUP BY句のみを含める必要があります(SPJGクエリ)。条件を満たさないマテリアライズドビューはエラーにはなりませんが、リライトには使用されません。
- マテリアライズドビューを作成する際に、
現在のクエリは以下の要件を満たしている必要があります:
- クエリは
SELECTクエリであり、集合クエリや階層クエリではなく、ウィンドウ関数も含まれていません。 FROM句には、マテリアライズドビューに登場するすべてのテーブルが含まれており、マテリアライズドビューには存在しないテーブルも含めることができます。また、結合順序が互換性があります。WHERE条件はマテリアライズドビューの部分集合であり、現在のクエリに集計がある場合は完全に一致している必要があります。例えば、マテリアライズドビューのWHEREがc1 > 10で、現在のクエリのWHEREがc1 > 10 AND c2 > 20の場合、マテリアライズドビューの条件 {c1 > 10} は現在のクエリの条件 {c1 > 10, c2 > 20} の部分集合です。- クエリに集計がない場合、マテリアライズドビューにも集計がない必要があります。
- クエリに集計がある場合、マテリアライズドビューに集計がないか、またはマテリアライズドビューにクエリのすべての
GROUP BY列が含まれている必要があります。集計を伴うマテリアライズドビューを使用してリライトする場合、FROMとWHEREが完全に一致している必要があります。 - 現在のクエリで使用されている
SELECT項目、WHERE、HAVING、GROUP BYなどの条件に含まれる列は、すべてマテリアライズドビューのSELECTステートメントに含まれる列である必要があります。
- クエリは
ルール/コストチェック
クエリのリライト時、OceanBaseデータベースの現在のバージョンではコストチェックは行われませんが、ルールチェックでは、リライト後の WHERE 条件が少なくとも1つのマテリアライズドビュー上のインデックスを使用できる必要があります。また、10個を超えるマテリアライズドビューが存在する場合、マテリアライズドビューによるクエリのリライトは最初の10個のマテリアライズドビューのみを試用します。
マテリアライズドビューによるリライト
マテリアライズドビューによるクエリのリライトを制御するシステム変数は以下のとおりです:
query_rewrite_enabled:マテリアライズドビューによるリライト機能を有効にするかどうかを設定します。この変数の詳細については、query_rewrite_enabledを参照してください。例:
SET query_rewrite_enabled = 'force';query_rewrite_integrity:マテリアライズドビューによるリライトのデータ一貫性チェックレベルを指定します。この変数の詳細については、query_rewrite_integrityを参照してください。例:
SET query_rewrite_integrity = 'stale_tolerated';
以下の例でマテリアライズドビューによるリライトを示します:
テーブル
test_tbl1を作成します。CREATE TABLE test_tbl1 (col1 INT, col2 INT, col3 INT);テーブル
test_tbl2を作成します。CREATE TABLE test_tbl2 (col1 INT, col2 INT, col3 INT);mv_test_tbl1_tbl2という名前のマテリアライズドビューを作成し、このマテリアライズドビューの自動リライトを有効にします。CREATE MATERIALIZED VIEW mv_test_tbl1_tbl2 ENABLE QUERY REWRITE AS SELECT t1.col1 col1, t1.col2 t1col2, t1.col3 t1col3, t2.col2 t2col2, t2.col3 t2col3 FROM test_tbl1 t1, test_tbl2 t2 WHERE t1.col1 = t2.col1;クエリ
SELECT count(*), test_tbl1.col1 col1 FROM test_tbl1, test_tbl2 WHERE test_tbl1.col1 = test_tbl2.col1 AND test_tbl2.col2 > 10 GROUP BY col1;を入力すると、マテリアライズドビューのクエリリライトが発生します。SELECT count(*), test_tbl1.col1 col1 FROM test_tbl1, test_tbl2 WHERE test_tbl1.col1 = test_tbl2.col1 AND test_tbl2.col2 > 10 GROUP BY col1; MV REWRITE ==> SELECT count(*), mv_test_tbl1_tbl2.col1 col1 FROM mv_test_tbl1_tbl2 WHERE mv_test_tbl1_tbl2.t2col2 > 10 GROUP BY mv_test_tbl1_tbl2.col1;
マテリアライズドビュークエリリライトの制御
マテリアライズドビュークエリリライトの制御には MV_REWRITE と NO_MV_REWRITE の2つのヒントがあり、これら2つのヒントの優先順位はシステム変数 query_rewrite_enabled よりも高いです。
MV_REWRITE
MV_REWRITE の構文は次のとおりです:
/*+ MV_REWRITE (@ queryblock [mv_name_list]) */
mv_name_list:
mv_name [, mv_name ...]
MV_REWRITE ヒントを単独で使用すると、マテリアライズドビュークエリリライトのルール/コストチェックをスキップし、使用可能なリライトを直接適用できます。ヒントの後に1つ以上のマテリアライズドビューを指定する場合、ルール/コストチェックをスキップするだけでなく、マテリアライズドビュークエリリライトは指定されたマテリアライズドビューのみを使用してリライトを試み、指定されていないすべてのマテリアライズドビューを無視します。
MV_REWRITE ヒントを使用してマテリアライズドビューを指定しても、ENABLE QUERY REWRITE (現在のマテリアライズドビューの自動リライトを有効にする) 句を持たないマテリアライズドビューの使用を強制することはできません。また、システム変数 query_rewrite_integrity が enforced に設定されている場合、非リアルタイムマテリアライズドビューの使用を強制することもできません。
NO_MV_REWRITE
NO_MV_REWRITE の構文は次のとおりです:
/*+ NO_MV_REWRITE (@ queryblock) */
マテリアライズドビュークエリリライトを禁止します。クエリブロックを指定できます。
マテリアライズドビュークエリリライト制御ヒントの使用例
基本テーブル
tbl2を作成します。CREATE TABLE tbl2 (col1 INT, col2 INT);基本テーブル
tbl2に2件のデータを挿入します。INSERT INTO tbl2 VALUES (1,2),(3,4);実行結果は次のとおりです:
Query OK, 2 rows affected Records: 2 Duplicates: 0 Warnings: 0マテリアライズドビュー
mv1_tbl2を作成し、現在のマテリアライズドビューの自動リライトを有効にします。CREATE MATERIALIZED VIEW mv1_tbl2 NEVER REFRESH ENABLE QUERY REWRITE AS SELECT * FROM tbl2;マテリアライズドビュー
mv2_tbl2を作成し、現在のマテリアライズドビューの自動リライトを有効にします。CREATE MATERIALIZED VIEW mv2_tbl2 NEVER REFRESH ENABLE QUERY REWRITE AS SELECT * FROM tbl2 WHERE tbl2.col1 > 1;システム変数
query_rewrite_integrityをstale_toleratedに設定します。説明
MV_REWRITEおよびNO_MV_REWRITEヒントの優先順位はシステム変数query_rewrite_enabledよりも高いため、query_rewrite_enabledを設定する必要はありません。ただし、非リアルタイムマテリアライズドビューを使用したリライトを有効にするには、query_rewrite_integrityをstale_toleratedに設定する必要があります。SET query_rewrite_integrity = 'stale_tolerated';MV_REWRITEヒントを使用してマテリアライズドビューを用いたリライトを試み、リライトコスト/ルールチェックをスキップします。以下の2つのクエリは、どちらもマテリアライズドビューmv1_tbl2を使用してリライトされます。/*+mv_rewrite*/は、リライト条件に合致するマテリアライズドビューを使用したリライトを試みます。リライト要件に合致するマテリアライズドビューが見つかると、その後のマテリアライズドビューは検討されず、リライトコスト/ルールチェックもスキップされます。EXPLAIN SELECT /*+mv_rewrite*/ count(*), col1 FROM tbl2 WHERE tbl2.col1 > 1 GROUP BY col1;実行結果は次のとおりです:
+------------------------------------------------------------------------------------+ | Query Plan | +------------------------------------------------------------------------------------+ | ===================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ----------------------------------------------------- | | |0 |HASH GROUP BY | |1 |3 | | | |1 |└─TABLE FULL SCAN|mv1_tbl2|1 |3 | | | ===================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output([T_FUN_COUNT(*)], [mv1_tbl2.col1]), filter(nil), rowset=16 | | group([mv1_tbl2.col1]), agg_func([T_FUN_COUNT(*)]) | | 1 - output([mv1_tbl2.col1]), filter([mv1_tbl2.col1 > 1]), rowset=16 | | access([mv1_tbl2.col1]), partitions(p0) | | is_index_back=false, is_global_index=false, filter_before_indexback[false], | | range_key([mv1_tbl2.__pk_increment]), range(MIN ; MAX)always true | +------------------------------------------------------------------------------------+ 14 rows in set/*+mv_rewrite(mv2_tbl2)*/は、mv2_tbl2を使用したリライトを試み、リライトコスト/ルールチェックをスキップします。EXPLAIN SELECT /*+mv_rewrite(mv2_tbl2)*/ count(*), col1 FROM tbl2 WHERE tbl2.col1 > 1 GROUP BY col1;実行結果は次のとおりです:
+-------------------------------------------------------------------------+ | Query Plan | +-------------------------------------------------------------------------+ | ===================================================== | | |ID|OPERATOR |NAME |EST.ROWS|EST.TIME(us)| | | ----------------------------------------------------- | | |0 |HASH GROUP BY | |1 |3 | | | |1 |└─TABLE FULL SCAN|mv2_tbl2|1 |3 | | | ===================================================== | | Outputs & filters: | | ------------------------------------- | | 0 - output([T_FUN_COUNT(*)], [mv2_tbl2.col1]), filter(nil), rowset=16 | | group([mv2_tbl2.col1]), agg_func([T_FUN_COUNT(*)]) | | 1 - output([mv2_tbl2.col1]), filter(nil), rowset=16 | | access([mv2_tbl2.col1]), partitions(p0) | | is_index_back=false, is_global_index=false, | | range_key([mv2_tbl2.__pk_increment]), range(MIN ; MAX)always true | +-------------------------------------------------------------------------+ 14 rows in set
クエリは
mv2_tbl2を使用したリライトを指定していますが、クエリ文のWHERE条件が要件を満たさないため、mv2_tbl2はリライトに使用できません。そのため、このクエリはマテリアライズドビューを使用したリライトを行いません。EXPLAIN SELECT /*+mv_rewrite(mv2_tbl2)*/ count(*), col1 FROM tbl2 WHERE tbl2.col1 < 1 GROUP BY col1;実行結果は次のとおりです:
+------------------------------------------------------------------------------------+ | Query Plan | +------------------------------------------------------------------------------------+ | ================================================= | | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| | | ------------------------------------------------- | | |0 |HASH GROUP BY | |1 |3 | | | |1 |└─TABLE FULL SCAN|tbl2|1 |3 | | | ================================================= | | Outputs & filters: | | ------------------------------------- | | 0 - output([T_FUN_COUNT(*)], [tbl2.col1]), filter(nil), rowset=16 | | group([tbl2.col1]), agg_func([T_FUN_COUNT(*)]) | | 1 - output([tbl2.col1]), filter([tbl2.col1 < 1]), rowset=16 | | access([tbl2.col1]), partitions(p0) | | is_index_back=false, is_global_index=false, filter_before_indexback[false], | | range_key([tbl2.__pk_increment]), range(MIN ; MAX)always true | +------------------------------------------------------------------------------------+ 14 rows in set/*+ no_mv_rewrite*/ヒントを使用すると、マテリアライズドビューを使用したリライトは行われません。EXPLAIN SELECT /*+no_mv_rewrite*/ count(*), col1 FROM tbl2 WHERE tbl2.col1 > 1 GROUP BY col1;実行結果は次のとおりです:
+------------------------------------------------------------------------------------+ | Query Plan | +------------------------------------------------------------------------------------+ | ================================================= | | |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| | | ------------------------------------------------- | | |0 |HASH GROUP BY | |1 |3 | | | |1 |└─TABLE FULL SCAN|tbl2|1 |3 | | | ================================================= | | Outputs & filters: | | ------------------------------------- | | 0 - output([T_FUN_COUNT(*)], [tbl2.col1]), filter(nil), rowset=16 | | group([tbl2.col1]), agg_func([T_FUN_COUNT(*)]) | | 1 - output([tbl2.col1]), filter([tbl2.col1 > 1]), rowset=16 | | access([tbl2.col1]), partitions(p0) | | is_index_back=false, is_global_index=false, filter_before_indexback[false], | | range_key([tbl2.__pk_increment]), range(MIN ; MAX)always true | +------------------------------------------------------------------------------------+ 14 rows in set
マテリアライズドビューによるクエリのリライトの適用シナリオ
OceanBaseデータベースのマテリアライズドビューによるクエリのリライトは、非集約マテリアライズドビューのFROM結合の互換性をサポートし、マテリアライズドビューに存在しないテーブルを含むクエリのリライトをサポートします。また、集約を伴うマテリアライズドビューのリライトや、集約のロールアップリフトによるリライトもサポートしています。
説明
以下の例でクエリステートメントが作成するマテリアライズドビューは、フル更新マテリアライズドビューです。増分更新マテリアライズドビューのクエリステートメントも、対応する条件を満たせば同様のシナリオでのクエリリライトをサポートします。
結合順序の互換性
マテリアライズドビューとクエリのFROM内の結合順序が異なる場合でも、両者の結合順序を変換した後に等価であれば、マテリアライズドビューによるリライトを使用できます。
マテリアライズドビューによるリライトでは、競合検出器を通じて、クエリの結合順序とマテリアライズドビューが互換性があるかどうかをチェックします。
例:
マテリアライズドビュー内のクエリステートメント:
SELECT t1.c1 t1c1, t2.c1 t2c1, t3.c1 t3c1
FROM t1 INNER JOIN t2 ON t1.c1 = t2.c1
INNER JOIN t3 ON t1.c1 = t3.c1;
現在のクエリステートメント:
SELECT t1.c1, t2.c1, t3.c1
FROM t1 INNER JOIN t3 ON t1.c1 = t3.c1, t2
WHERE t1.c1 = t2.c1;
クエリリライト後のステートメント:
SELECT mv.t1c1, mv.t2c1, mv.t3c1
FROM mv;
結合タイプの互換性
マテリアライズドビューの結合タイプがクエリと異なる場合でも、補償述語を追加することで互換可能であれば、マテリアライズドビューによるリライトを使用できます。
結合タイプの互換性がリライトを許可するには、以下の条件を満たす必要があります:
- マテリアライズドビューの結合には、より多くのNULL行が含まれている。例えば、クエリに
INNER JOINが必要な場合、マテリアライズドビューがLEFT OUTER JOINまたはFULL OUTER JOINである。 - 現在の結合ノードには、NULL行をフィルタリングするために使用できる非NULL列が存在する。
- 現在のノード上のフィルタリング述語を
WHEREにロールアップできる。
例:
マテリアライズドビュー内のクエリステートメント:
SELECT t1.c1 t1c1, t2.pk t2pk
FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1;
現在のクエリステートメント:
SELECT t1.c1
FROM t1, t2
WHERE t1.c1 = t2.c1;
クエリリライト後のステートメント:
SELECT mv.t1c1
FROM mv
WHERE mv.t2pk IS NOT NULL;
マテリアライズドビューに含まれないテーブルのクエリ
クエリにマテリアライズドビューに含まれないテーブルが含まれる場合、マテリアライズドビューのリライトは接続順序をチェックし、余分なテーブルがマテリアライズドビューの後に接続できるかどうかを確認します。可能であれば、リライトが実行されます。
例:
マテリアライズドビュー内のクエリステートメント:
SELECT t1.c1 t1c1, t1.pk t1pk
FROM t1 LEFT JOIN t2 ON t1.c1 = t2.c1;
現在のクエリステートメント:
SELECT t1.c1
FROM t1, t2, t3
WHERE t1.c1 = t2.c1
AND t3.c1 = t1.c1;
クエリのリライト後のステートメント:
SELECT mv.t1c1
FROM mv, t3
WHERE t3.c1 = mv.t1c1
AND mv.t1pk IS NOT NULL;
集計を伴うマテリアライズドビューのリライト
集計を伴うマテリアライズドビューを使用してリライトする場合、クエリはマテリアライズドビューの FROM 句の順序と互換性があり、マテリアライズドビューに含まれていないテーブルを含むことはできません。また、クエリの WHERE 句もマテリアライズドビューと完全に一致している必要があります。
例:
マテリアライズドビュー内のクエリステートメント:
SELECT SUM(c1) sumc1, c2, c3
FROM t1
WHERE c1 > 10
GROUP BY c2, c3;
現在のクエリステートメント:
SELECT SUM(c1), c2, c3
FROM t1
WHERE c1 > 10
GROUP BY c2, c3;
クエリのリライト後のステートメント:
SELECT mv.sumc1, mv.c2, mv.c3
FROM mv;
集計のアップロールによるリライト
マテリアライズドビューの集計列とクエリの集計列が異なる場合、クエリの集計列がマテリアライズドビューの集計列の部分集合である場合、マテリアライズドビューを使用したリライトが可能です。この場合、一部の集計関数のみがサポートされ、その他の要件は集計を伴うマテリアライズドビューを使用したリライトと同じです。
集計のアップロールでサポートされている集計関数:COUNT、SUM、BIT_AND、BIT_OR、BIT_XOR、MIN、MAX。
例:
マテリアライズドビュー内のクエリステートメント:
SELECT SUM(c1) sumc1, COUNT(c1) cntc1, c2, c3
FROM t1
WHERE c1 > 10
GROUP BY c2, c3;
現在のクエリステートメント:
SELECT SUM(c1), COUNT(c1), c2
FROM t1
WHERE c1 > 10
AND c3 = 10
GROUP BY c2;
クエリのリライト後のステートメント:
SELECT SUM(mv.sumc1), COUNT_SUM(mv.cntc1), mv.c2
FROM mv
WHERE mv.c3 = 10
GROUP BY mv.c2;