クエリリライトにより、AnalyticDB for MySQL は SQL を変更することなく、クエリを自動的にマテリアライズドビューにリダイレクトできます。クエリがマテリアライズドビューと一致すると、エンジンはベーステーブルをスキャンする代わりに事前に計算された結果を読み取るため、クエリレイテンシーを大幅に削減できます。
前提条件
AnalyticDB for MySQL クラスターは V3.1.4.0 以降を実行しています。
説明Data Lakehouse Edition クラスターのマイナーバージョンを確認するには、
SELECT adb_version();を実行します。マイナーバージョンをアップグレードするには、テクニカルサポートにお問い合わせください。Data Warehouse Edition クラスターのマイナーバージョンを表示およびアップグレードするには、「マイナーバージョンのアップグレード」をご参照ください。
マテリアライズドビューを使用するには、次の権限が必要です:
マテリアライズドビューが存在するデータベースに対する CREATE 権限。
マテリアライズドビューのすべてのベーステーブルの関連列、またはテーブル全体に対する SELECT 権限。
自動的にリフレッシュされるマテリアライズドビューを作成するには、次の 2 つの権限も必要です:
任意の IP アドレス (つまり、
'%') から AnalyticDB for MySQL に接続する権限。マテリアライズドビュー、またはマテリアライズドビューが存在するデータベース内のすべてのテーブルに対する INSERT 権限。この権限がない場合、マテリアライズドビューのデータはリフレッシュできません。
仕組み
AnalyticDB for MySQL は、受信した各クエリを、クエリリライトが有効になっているすべてのマテリアライズドビューと比較します。一致するものが見つかった場合、エンジンはクエリを書き換えて、ベーステーブルの代わりにマテリアライズドビューから読み取ります。次の順序で適用される 2 つの一致戦略が使用されます:
完全一致リライト — クエリ構造がマテリアライズドビューの定義と同一である場合。これは、より制約の少ないシンプルな戦略です。
高度なクエリリライト — 構造が異なる場合。エンジンは書き換えルール (FILTER、JOIN、AGGREGATION、集計ロールアップ、SUBQUERIES、QUERY PARTIAL、UNION) を適用して、マテリアライズドビューにクエリまたはその一部を解決するのに十分なデータが含まれているかどうかを判断します。同じ文内の異なるサブクエリが、異なるマテリアライズドビューと一致する場合があります。
すべてのクエリリライトは STALE_TOLERATED レベルで動作します:エンジンは、マテリアライズドビューにベーステーブルから同期されていないステイルデータが含まれている場合でも、クエリを書き換えます。これにより、書き換えの対象範囲が最大化されますが、結果が最新の挿入や更新を反映していない可能性があります。レイテンシーの影響を受けやすいクエリを実行する前に、マテリアライズドビューをリフレッシュしてください。詳細については、「マテリアライズドビューの完全リフレッシュの設定」をご参照ください。
クエリリライトの有効化
クエリリライトは、次の 2 つの方法のいずれかで有効化します:
作成時に、
CREATE MATERIALIZED VIEW文にENABLE QUERY REWRITE句を含めます。「マテリアライズドビューの作成 — パラメーター」をご参照ください。作成後に、次を実行します:
ALTER MATERIALIZED VIEW <mv_name> ENABLE QUERY REWRITE;「マテリアライズドビューの管理」をご参照ください。
クエリリライトの無効化
クエリリライトは、次の 2 つの方法のいずれかで無効化します:
特定のマテリアライズドビューの場合:
ALTER MATERIALIZED VIEW <mv_name> DISABLE QUERY REWRITE;特定のクエリの場合、
SELECT文の前にヒントを追加します:/*+MV_QUERY_REWRITE_ENABLED=false*/ SELECT ...
クエリリライトの動作確認
クエリリライトを有効にした後、EXPLAIN を使用して、エンジンがマテリアライズドビューから読み取っていることを確認します。
例
クエリリライトを有効にしてマテリアライズドビューを作成します。
CREATE MATERIALIZED VIEW adb_mv REFRESH START WITH now() + interval 1 day ENABLE QUERY REWRITE AS SELECT course_id, course_name, max(course_grade) AS max_grade FROM tb_courses;クエリリライトを有効にした後、クエリに対して
EXPLAINを実行します。EXPLAIN SELECT course_id, course_name, max(course_grade) AS max_grade FROM tb_courses;実行計画を確認します。クエリリライトがアクティブな場合、
TableScan行にはベーステーブル (tb_courses) ではなく、マテリアライズドビュー名 (adb_mv) が表示されます。+---------------+ | Plan Summary | +---------------+ 1- Output[ Query plan ] {Est rowCount: 1.0} 2 -> Exchange[GATHER] {Est rowCount: 1.0} 3 - TableScan {table: adb_mv, Est rowCount: 1.0}実行計画にまだ
TableScan {table: tb_courses, ...}が表示されている場合、クエリリライトは有効になっていません。「トラブルシューティング」セクションをご確認ください。
書き換えの範囲
以下の例は、高度なクエリリライトメソッドでサポートされている各書き換えルールを示しています。すべての例で、同じ 4 つのテーブルを使用します:
CREATE TABLE part (
partkey INTEGER NOT NULL,
name VARCHAR(55) NOT NULL,
type VARCHAR(25) NOT NULL
);
CREATE TABLE lineitem (
orderkey BIGINT,
partkey BIGINT NOT NULL,
suppkey BIGINT NOT NULL,
extendedprice DOUBLE NOT NULL,
discount DOUBLE NOT NULL,
returnflag CHAR(1) NOT NULL,
linestatus CHAR(1) NOT NULL,
shipdate DATE NOT NULL,
shipmode VARCHAR(25) NOT NULL,
commitdate DATE NOT NULL,
receiptdate DATE NOT NULL
);
CREATE TABLE orders (
orderkey BIGINT PRIMARY KEY,
custkey BIGINT NOT NULL,
orderstatus VARCHAR(1) NOT NULL,
totalprice DOUBLE NOT NULL,
orderdate DATE NOT NULL
);
CREATE TABLE partsupp (
partkey INTEGER NOT NULL PRIMARY KEY,
suppkey INTEGER NOT NULL,
availqty INTEGER NOT NULL,
supplycost DECIMAL(15,2) NOT NULL
);完全一致リライト
クエリ構造がマテリアライズドビューの定義と同じである場合、エンジンはクエリを直接書き換えます。
クエリ
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)),
COUNT(*) AS count_order
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;マテリアライズドビュー
CREATE MATERIALIZED VIEW mv0
REFRESH NEXT now() + interval 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price,
COUNT(*) AS count_order
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;書き換えられたクエリ
SELECT returnflag, linestatus, sum_disc_price, count_order
FROM mv0;高度なクエリリライト
FILTER
クエリの述語がマテリアライズドビューの述語よりも狭い場合、エンジンはマテリアライズドビューのスキャンに WHERE 句を追加して、欠落しているフィルターを適用します。クエリ内の式がマテリアライズドビューに存在しない場合、エンジンはその式をビューから計算することも試みます。
クエリ
SELECT
l.shipmode,
l.extendedprice * (1 - l.discount) AS disc_price
FROM orders AS o, lineitem AS l
WHERE o.orderkey = l.orderkey
AND l.shipmode IN ('REG AIR', 'TRUCK')
AND l.commitdate < l.receiptdate
AND l.shipdate < l.commitdate;マテリアライズドビュー
CREATE MATERIALIZED VIEW mv1
REFRESH NEXT now() + interval 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.shipmode,
l.extendedprice,
l.discount
FROM orders AS o, lineitem AS l
WHERE o.orderkey = l.orderkey
AND l.commitdate < l.receiptdate
AND l.shipdate < l.commitdate;書き換えられたクエリ
SELECT
shipmode,
extendedprice * (1 - discount) AS disc_price,
discount
FROM mv1
WHERE shipmode IN ('REG AIR', 'TRUCK');JOIN
クエリとマテリアライズドビューの結合関係が異なる場合、エンジンはマテリアライズドビューから必要な結合を導出します。たとえば、外部結合を持つマテリアライズドビューは、null 行を除外することで、内部結合を必要とするクエリを満たすことができます。
サポートされている結合タイプ:内部結合、外部結合、左結合、右結合。
クエリ
SELECT
p.type,
p.partkey,
ps.suppkey
FROM part AS p, partsupp AS ps
WHERE p.partkey = ps.partkey
AND p.type NOT LIKE 'MEDIUM POLISHED%';マテリアライズドビュー
CREATE MATERIALIZED VIEW mv2
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
p.type,
p.partkey,
ps.suppkey
FROM partsupp AS ps
INNER JOIN part AS p ON p.partkey = ps.partkey
WHERE p.type NOT LIKE 'MEDIUM POLISHED%';書き換えられたクエリ
SELECT type, partkey, suppkey
FROM mv2;AGGREGATION
クエリまたはマテリアライズドビューが異なる GROUP BY 句または集計関数を使用する場合、エンジンは AGGREGATION ルールを使用して、マテリアライズドビューから同じ集計関数を生成します。
クエリ
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;マテリアライズドビュー
CREATE MATERIALIZED VIEW mv3
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price,
COUNT(*) AS count_order
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;書き換えられたクエリ
SELECT returnflag, linestatus, sum_disc_price, count_order
FROM mv3;集計ロールアップ
クエリがマテリアライズドビューの GROUP BY フィールドのサブセットでグループ化する場合、エンジンは事前に計算された集計をロールアップします。
クエリ
SELECT
l.returnflag,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price,
COUNT(*) AS count_order
FROM lineitem AS l
WHERE l.returnflag = 'R'
GROUP BY l.returnflag;マテリアライズドビュー
CREATE MATERIALIZED VIEW mv4
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.returnflag,
l.linestatus,
SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price,
COUNT(*) AS count_order
FROM lineitem AS l
GROUP BY l.returnflag, l.linestatus;書き換えられたクエリ
SELECT
returnflag,
linestatus,
sum_disc_price,
count_order
FROM mv4
WHERE returnflag = 'R'
GROUP BY returnflag;SUBQUERIES
クエリがベーステーブルの代わりにサブクエリを使用する場合、エンジンはマテリアライズドビューがテーブル全体をカバーしているかどうかを確認し、サブクエリのフィルターを書き換えられたスキャンにプッシュします。
クエリ
SELECT
p.type,
p.partkey,
ps.suppkey
FROM part AS p,
(SELECT * FROM partsupp WHERE suppkey > 10) ps
WHERE p.partkey = ps.partkey;マテリアライズドビュー
CREATE MATERIALIZED VIEW mv5
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
p.type,
p.partkey,
ps.suppkey
FROM part AS p, partsupp AS ps
WHERE p.partkey = ps.partkey;書き換えられたクエリ
SELECT type, partkey, suppkey
FROM mv5
WHERE suppkey > 10;QUERY PARTIAL
クエリがマテリアライズドビューでカバーされていないテーブルを参照する場合、エンジンはマテリアライズドビューを欠落しているテーブルと結合します。
クエリ
SELECT
p.type,
p.partkey,
ps.suppkey
FROM part AS p, partsupp AS ps
WHERE p.partkey = ps.partkey
AND p.type NOT LIKE 'MEDIUM POLISHED%';マテリアライズドビュー
CREATE MATERIALIZED VIEW mv6
REFRESH NEXT now() + INTERVAL 1 day
ENABLE QUERY REWRITE
AS
SELECT
p.type,
p.partkey
FROM part AS p
WHERE p.type NOT LIKE 'MEDIUM POLISHED%';書き換えられたクエリ
SELECT
mv6.type,
mv6.partkey,
ps.suppkey
FROM mv6, partsupp AS ps
WHERE mv6.partkey = ps.partkey;UNION
マテリアライズドビューがクエリの日付または値の範囲の一部のみをカバーしている場合、エンジンはカバーされている部分をマテリアライズドビューから取得し、残りの行をベーステーブルから直接フェッチし、その結果を UNION ALL で結合します。
クエリ
SELECT
l.linestatus,
COUNT(*) AS count_order
FROM lineitem AS l
WHERE l.shipdate >= DATE '1998-01-01'
GROUP BY l.linestatus;マテリアライズドビュー (shipdate >= 2000-01-01 のみカバー)
CREATE MATERIALIZED VIEW mv7
REFRESH NEXT now() + interval 1 day
ENABLE QUERY REWRITE
AS
SELECT
l.linestatus,
COUNT(*) AS count_order
FROM lineitem AS l
WHERE l.shipdate >= DATE '2000-01-01'
GROUP BY l.linestatus;書き換えられたクエリ
SELECT linestatus, count_order
FROM (
SELECT linestatus, count_order
FROM mv7
UNION ALL
SELECT
l.linestatus,
COUNT(*) AS count_order
FROM lineitem AS l
WHERE l.shipdate >= DATE '1998-01-01' AND l.shipdate < DATE '2000-01-01'
GROUP BY l.linestatus
)
GROUP BY linestatus;制限事項
完全一致リライト
完全一致リライトは、マテリアライズドビューに以下が含まれる場合、有効になりません:
非決定性関数:
NOW、CURRENT_TIMESTAMP、RANDOMユーザー定義関数 (UDF)
高度なクエリリライト
高度なクエリリライトは、マテリアライズドビューに以下のいずれかが含まれる場合、有効になりません:
ORDER BY、LIMIT、またはOFFSET句UNIONまたはUNION ALL句GROUP BY句内のGROUPING SETS、CUBE、またはROLLUPウィンドウ関数
FULL OUTER JOINシステムテーブル
相関サブクエリ
非決定性関数:
NOW、CURRENT_TIMESTAMP、RANDOMUDF
HAVING句SELF JOIN
クエリリライトが有効にならない文の種類
クエリリライトは、マテリアライズドビューの定義に関係なく、以下の種類の文に埋め込まれたクエリには適用されません:
CREATE TABLE AS SELECTINSERT INTO SELECTINSERT OVERWRITE SELECTREPLACE INTO SELECTDELETEまたはUPDATE
フィルターや集計のない単一テーブルクエリ
クエリリライトは、フィルター条件や集計関数がない単一テーブルのクエリに対しては有効になりません。
トラブルシューティング
マテリアライズドビューを作成した後、クエリリライトが有効になりません。
最も一般的な原因から確認してください:
マテリアライズドビューのクエリリライトが有効になっていません。
ALTER MATERIALIZED VIEW <mv_name> ENABLE QUERY REWRITE;を実行して、再試行してください。マテリアライズドビューが制限に抵触しています。「制限事項」セクションを確認し、マテリアライズドビューの定義にサポートされていない句や関数が含まれていないか確認してください。
マテリアライズドビューに対する SELECT 権限がありません。クエリを実行するアカウントに必要な権限を付与します:
GRANT SELECT ON <database>.<mv_name> TO '<account>';詳細については、「マテリアライズドビューからのデータクエリ」トピックの「必要な権限」セクションをご参照ください。