メインコンテンツまでスキップ
に最終更新

非同期マテリアライズドビューの管理とクエリ

非同期マテリアライズドビューは、Doris が提供する事前計算に基づく高速化機能です。この記事では、実際の利用手順に沿って、次のトピックを順に説明します。

  • マテリアライズドビューの作成:構文、更新ポリシー、パーティション設定。
  • マテリアライズドビューのクエリ:直接クエリと透過的なクエリ書き換え。
  • マテリアライズドビューの運用:変更、削除、監視、関連パラメータの設定。

読み進める前に、以下を確認してください。

  • 非同期マテリアライズドビューの基本概念と適用シナリオを理解していること。
  • 新しいオプティマイザが有効になっていること(enable_nereids_planner = true)。
  • 基本的なテーブル作成と SQL 構文に習熟していること。

1. マテリアライズドビューの作成​

1.1 権限​

マテリアライズドビューの作成には、次の2種類の権限が必要です。

  • マテリアライズドビューの作成権限:テーブルの作成権限と同じです。
  • ベーステーブルのクエリ権限:SELECT 権限と同じです(マテリアライズドビューの定義 SQL が参照するベーステーブルに対するクエリ権限)。

1.2 作成構文​

非同期マテリアライズドビューの作成構文全体は次のとおりです。

CREATE MATERIALIZED VIEW
[ IF NOT EXISTS ] <materialized_view_name>
[ (<columns_definition>) ]
[ BUILD <build_mode> ]
[ REFRESH <refresh_method> [refresh_trigger]]
[ [DUPLICATE] KEY (<key_cols>) ]
[ COMMENT '<table_comment>' ]
[ PARTITION BY (
{ <partition_col>
| DATE_TRUNC(<partition_col>, <partition_unit>) }
)]
[ DISTRIBUTED BY { HASH (<distribute_cols>) | RANDOM }
[ BUCKETS { <bucket_count> | AUTO } ]
]
[ PROPERTIES (
-- Table property
<table_property>
-- Additional table properties
[ , ... ])
]
AS <query>

1.3 更新設定​

更新設定は、更新タイミング(build_mode)、更新方法(refresh_method)、トリガー方法(refresh_trigger)の3種類のパラメータで構成されます。

1.3.1 パラメータの概要​

カテゴリ値説明
更新タイミングIMMEDIATE作成直後に更新します(デフォルト)。
更新タイミングDEFERRED作成後の更新を延期します。
更新方法COMPLETE全パーティションを更新します。
更新方法AUTO可能な場合は増分更新し、変更を検出できない場合は全件更新に切り替えます。
トリガー方法ON MANUALユーザーが SQL ステートメントで手動でトリガーします。
トリガー方法ON SCHEDULE指定した間隔で定期的にトリガーします。
トリガー方法ON COMMITベーステーブルのデータが変更されたときに自動的にトリガーします(Apache Doris 2.1.4 以降でサポート)。

1.3.2 ON MANUAL:手動トリガー​

SQL ステートメントでマテリアライズドビューの更新をトリガーします。方法は3つあります。

方法 1:前回の更新以降にベーステーブルのパーティションデータが変更されたかを検出し、変更されたパーティションのみを更新します。

REFRESH MATERIALIZED VIEW mvName AUTO;
ヒント
  • マテリアライズドビューの定義 SQL が参照するベーステーブルが JDBC テーブルの場合、Doris はテーブルのデータ変更を検出できません。そのため、更新時には COMPLETE を指定する必要があります。指定しないと、ベーステーブルにはデータがあるのにマテリアライズドビューにはない状態になることがあります。
  • 現在、Doris がデータ変更を検出できるのは内部テーブルと Hive データソースのテーブルのみです。その他のデータソースにも順次対応しています。

方法 2:ベーステーブルのパーティションデータの変更確認を省略し、マテリアライズドビューの全パーティションを直接更新します。

REFRESH MATERIALIZED VIEW mvName COMPLETE;

方法 3:指定したパーティションのみを更新します。

REFRESH MATERIALIZED VIEW mvName partitions(partitionName1, partitionName2);
ヒント
  • partitionName は SHOW PARTITIONS FROM mvName で取得できます。
  • Hive のベーステーブルのパーティションデータ変更の検出は、バージョン 2.1.3 以降でサポートされています。その他の外部テーブルはまだサポートされていません。内部テーブルは常にサポートされています。

1.3.3 ON SCHEDULE:定期トリガー​

作成ステートメントで更新間隔を指定します。refreshUnit には minute、hour、day、week などを指定できます。

例 1:全件更新(REFRESH COMPLETE)。10時間ごとに全パーティションを更新します。

CREATE MATERIALIZED VIEW mv_6
REFRESH COMPLETE ON SCHEDULE EVERY 10 hour
AS
SELECT * FROM lineitem;

例 2:可能な場合は増分更新(REFRESH AUTO)。10時間ごとに更新します。データが変更されたパーティションのみを更新し、増分更新ができない場合は全件更新に切り替えます。

CREATE MATERIALIZED VIEW mv_7
REFRESH AUTO ON SCHEDULE EVERY 10 hour
PARTITION BY (l_shipdate)
AS
SELECT * FROM lineitem;
ヒント

バージョン 2.1.3 以降、Doris は Hive テーブルで更新が必要なパーティションを自動的に計算できます。

1.3.4 ON COMMIT:自動トリガー​

ヒント

この機能は Apache Doris 2.1.4 以降でサポートされています。

ベーステーブルのデータが変更されると、対応するマテリアライズドビューの更新が自動的にトリガーされます。更新対象のパーティション範囲は、定期トリガーの場合と同じです。

CREATE MATERIALIZED VIEW mv_8
REFRESH AUTO ON COMMIT
PARTITION BY (l_shipdate)
AS
SELECT * FROM lineitem;

ベーステーブル lineitem のパーティション t1 のデータが変更されると、マテリアライズドビューの対応するパーティションの更新が自動的にトリガーされます。

注意

ベーステーブルのデータが頻繁に変更される場合、このトリガー方法は推奨しません。更新タスクが頻繁に作成され、リソースを過度に消費するためです。

詳細は REFRESH MATERIALIZED VIEW を参照してください。

1.3.5 完全な例​

以下の一連の例で、更新の仕組みを示します。まず、ベーステーブルを作成してデータを初期化します。

CREATE TABLE IF NOT EXISTS lineitem (
l_orderkey integer not null,
l_partkey integer not null,
l_suppkey integer not null,
l_linenumber integer not null,
l_quantity decimalv3(15,2) not null,
l_extendedprice decimalv3(15,2) not null,
l_discount decimalv3(15,2) not null,
l_tax decimalv3(15,2) not null,
l_returnflag char(1) not null,
l_linestatus char(1) not null,
l_shipdate date not null,
l_commitdate date not null,
l_receiptdate date not null,
l_shipinstruct char(25) not null,
l_shipmode char(10) not null,
l_comment varchar(44) not null
)
DUPLICATE KEY(l_orderkey, l_partkey, l_suppkey, l_linenumber)
PARTITION BY RANGE(l_shipdate)
(FROM ('2023-10-17') TO ('2023-11-01') INTERVAL 1 DAY)
DISTRIBUTED BY HASH(l_orderkey) BUCKETS 3;

INSERT INTO lineitem VALUES
(1, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-10-17', '2023-10-17', '2023-10-17', 'a', 'b', 'yyyyyyyyy'),
(2, 4, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-10-18', '2023-10-18', '2023-10-18', 'a', 'b', 'yyyyyyyyy'),
(3, 2, 4, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-10-19', '2023-10-19', '2023-10-19', 'a', 'b', 'yyyyyyyyy');

CREATE TABLE IF NOT EXISTS orders (
o_orderkey integer not null,
o_custkey integer not null,
o_orderstatus char(1) not null,
o_totalprice decimalv3(15,2) not null,
o_orderdate date not null,
o_orderpriority char(15) not null,
o_clerk char(15) not null,
o_shippriority integer not null,
o_comment varchar(79) not null
)
DUPLICATE KEY(o_orderkey, o_custkey)
PARTITION BY RANGE(o_orderdate)(
FROM ('2023-10-17') TO ('2023-11-01') INTERVAL 1 DAY)
DISTRIBUTED BY HASH(o_orderkey) BUCKETS 3;

INSERT INTO orders VALUES
(1, 1, 'o', 9.5, '2023-10-17', 'a', 'b', 1, 'yy'),
(1, 1, 'o', 10.5, '2023-10-18', 'a', 'b', 1, 'yy'),
(2, 1, 'o', 11.5, '2023-10-19', 'a', 'b', 1, 'yy'),
(3, 1, 'o', 12.5, '2023-10-19', 'a', 'b', 1, 'yy');

CREATE TABLE IF NOT EXISTS partsupp (
ps_partkey INTEGER NOT NULL,
ps_suppkey INTEGER NOT NULL,
ps_availqty INTEGER NOT NULL,
ps_supplycost DECIMALV3(15,2) NOT NULL,
ps_comment VARCHAR(199) NOT NULL
)
DUPLICATE KEY(ps_partkey, ps_suppkey)
DISTRIBUTED BY HASH(ps_partkey) BUCKETS 3;

INSERT INTO partsupp VALUES
(2, 3, 9, 10.01, 'supply1'),
(4, 3, 10, 11.01, 'supply2'),
(2, 3, 10, 11.01, 'supply3');

例 1:作成直後の増分更新 + 手動トリガー

更新タイミングは作成直後(BUILD IMMEDIATE)、更新方法は可能な場合に増分更新(REFRESH AUTO)、トリガー方法は手動(ON MANUAL)です。パーティション分割されていないマテリアライズドビューにはパーティションが1つしかないため、ベーステーブルのデータに変更があると全件更新がトリガーされます。

CREATE MATERIALIZED VIEW mv_1_0
BUILD IMMEDIATE
REFRESH AUTO
ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT
l_linestatus,
to_date(o_orderdate) as date_alias,
o_shippriority
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey;

例 2:延期した全件更新 + スケジュールトリガー

更新タイミングは延期(BUILD DEFERRED)、更新方法は全件更新(REFRESH COMPLETE)です。初回更新時刻は 2024-12-01 20:30:00 で、その後は1日1回更新します。

ヒント

STARTS で指定する時刻は現在時刻より後でなければなりません。BUILD IMMEDIATE を指定すると、作成直後に1回更新され、その後は 2024-12-01 20:30:00 から1日1回更新されます。

CREATE MATERIALIZED VIEW mv_1_1
BUILD DEFERRED
REFRESH COMPLETE
ON SCHEDULE EVERY 1 DAY STARTS '2024-12-01 20:30:00'
PROPERTIES ('replication_num' = '1')
AS
SELECT
l_linestatus,
to_date(o_orderdate) as date_alias,
o_shippriority
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey;

例 3:作成直後の全件更新 + 自動トリガー

更新タイミングは作成直後(BUILD IMMEDIATE)、更新方法は全件更新(REFRESH COMPLETE)、トリガー方法は自動(ON COMMIT)です。orders または lineitem テーブルのデータが変更されると、更新が自動的にトリガーされます。

CREATE MATERIALIZED VIEW mv_1_1
BUILD IMMEDIATE
REFRESH COMPLETE
ON COMMIT
PROPERTIES ('replication_num' = '1')
AS
SELECT
l_linestatus,
to_date(o_orderdate) as date_alias,
o_shippriority
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey;

1.4 パーティション設定​

パーティション分割されたマテリアライズドビューを作成する場合は、PARTITION BY を指定する必要があります。パーティション列が参照する式には、date_trunc 関数と識別子しか使用できません。

1.4.1 有効なパーティション列の例​

パーティション列が参照する列では、date_trunc 関数のみを使用します。パーティション分割されたマテリアライズドビューの更新方法には通常 AUTO を指定します。

CREATE MATERIALIZED VIEW mv_2_0
BUILD IMMEDIATE
REFRESH AUTO
ON MANUAL
PARTITION BY (order_date_month)
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT
l_linestatus,
date_trunc(o_orderdate, 'month') as order_date_month,
o_shippriority
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey;

1.4.2 無効なパーティション列の例​

次のステートメントではパーティション列に date_add() 関数を使用しているため、マテリアライズドビューの作成に失敗します。

CREATE MATERIALIZED VIEW mv_2_1
BUILD IMMEDIATE REFRESH AUTO ON MANUAL
PARTITION BY (order_date_month)
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT
l_linestatus,
date_trunc(date_add(o_orderdate, INTERVAL 2 DAY), 'month') as order_date_month,
o_shippriority
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey;

エラーメッセージ:because column to check use invalid implicit expression, invalid expression is days_add(o_orderdate#4, 2)。

1.4.3 ベーステーブルの複数列によるパーティション分割​

現在、複数列によるパーティション分割をサポートしているのは Hive 外部テーブルのみです。たとえば、第1階層を日付、第2階層を地域でパーティション分割した場合、マテリアライズドビューはどちらの階層のパーティション列も自身のパーティション列として選択できます。

Hive テーブルの作成ステートメント:

CREATE TABLE hive1 (
`k1` int)
PARTITIONED BY (
`year` int,
`region` string)
STORED AS ORC;

ALTER TABLE hive1 ADD IF NOT EXISTS
PARTITION(year=2020, region="bj")
PARTITION(year=2020, region="sh")
PARTITION(year=2021, region="bj")
PARTITION(year=2021, region="sh")
PARTITION(year=2022, region="bj")
PARTITION(year=2022, region="sh");

シナリオ 1:year をパーティション列として使用する。 マテリアライズドビュー mv_hive には、('2020')、('2021')、('2022') の3つのパーティションが作成されます。

CREATE MATERIALIZED VIEW mv_hive
BUILD DEFERRED REFRESH AUTO ON MANUAL
PARTITION BY (`year`)
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT k1, year, region FROM hive1;

シナリオ 2:region をパーティション列として使用する。 マテリアライズドビュー mv_hive2 には、('bj') と ('sh') の2つのパーティションが作成されます。

CREATE MATERIALIZED VIEW mv_hive2
BUILD DEFERRED REFRESH AUTO ON MANUAL
PARTITION BY (`region`)
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT k1, year, region FROM hive1;

1.4.4 ベーステーブルのパーティションの一部のみを使用する​

適用シナリオ:ベーステーブルに多数のパーティションがあり、マテリアライズドビューでは最近の「ホット」データだけを対象にしたい場合です。

ベーステーブルの作成ステートメント:

CREATE TABLE t1 (
`k1` INT,
`k2` DATE NOT NULL
) ENGINE=OLAP
DUPLICATE KEY(`k1`)
COMMENT 'OLAP'
PARTITION BY range(`k2`)
(
PARTITION p26 VALUES [("2024-03-26"),("2024-03-27")),
PARTITION p27 VALUES [("2024-03-27"),("2024-03-28")),
PARTITION p28 VALUES [("2024-03-28"),("2024-03-29"))
)
DISTRIBUTED BY HASH(`k1`) BUCKETS 2;

マテリアライズドビューは直近1日分のデータだけを同期します。現在時刻が 2024-03-28 xx:xx:xx なら、マテリアライズドビューにはパーティション [("2024-03-28"),("2024-03-29")] だけが存在します。

CREATE MATERIALIZED VIEW mv1
BUILD DEFERRED REFRESH AUTO ON MANUAL
PARTITION BY (`k2`)
DISTRIBUTED BY RANDOM BUCKETS 2
PROPERTIES (
'partition_sync_limit' = '1',
'partition_sync_time_unit' = 'DAY'
)
AS
SELECT * FROM t1;

1日後、時刻が 2024-03-29 xx:xx:xx になると、t1 に新しいパーティション [("2024-03-29"),("2024-03-30")] が追加されます。マテリアライズドビューを更新すると、マテリアライズドビューにはパーティション [("2024-03-29"),("2024-03-30")] だけが存在します。

ヒント

パーティション列が文字列型の場合、マテリアライズドビューのプロパティ partition_date_format を設定できます。たとえば %Y-%m-%d を指定します。

1.4.5 パーティションのロールアップ​

ヒント

範囲パーティション分割は Doris 2.1.5 以降でサポートされています。

適用シナリオ:ベーステーブルのデータを集計すると、各パーティションのデータ量が大幅に減る場合です。パーティションのロールアップにより、マテリアライズドビューのパーティション数を減らせます。

ベーステーブルの作成ステートメント:

CREATE TABLE `t1` (
`k1` LARGEINT NOT NULL,
`k2` DATE NOT NULL
) ENGINE=OLAP
DUPLICATE KEY(`k1`)
COMMENT 'OLAP'
PARTITION BY range(`k2`)
(
PARTITION p_20200101 VALUES [("2020-01-01"),("2020-01-02")),
PARTITION p_20200102 VALUES [("2020-01-02"),("2020-01-03")),
PARTITION p_20200201 VALUES [("2020-02-01"),("2020-02-02"))
)
DISTRIBUTED BY HASH(`k1`) BUCKETS 2;

月単位でロールアップ:マテリアライズドビューには、[("2020-01-01","2020-02-01")] と [("2020-02-01","2020-03-01")] の2つのパーティションが含まれます。

CREATE MATERIALIZED VIEW mv_3
BUILD DEFERRED REFRESH AUTO ON MANUAL
PARTITION BY (date_trunc(`k2`, 'month'))
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT * FROM t1;

年単位でロールアップ:マテリアライズドビューに含まれるパーティションは [("2020-01-01","2021-01-01")] の1つだけです。

CREATE MATERIALIZED VIEW mv_4
BUILD DEFERRED REFRESH AUTO ON MANUAL
PARTITION BY (date_trunc(`k2`, 'year'))
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT * FROM t1;
ヒント

パーティション列が文字列型の場合、partition_date_format プロパティを設定して日付形式を指定できます。たとえば '%Y-%m-%d' を指定します。

詳細は CREATE ASYNC MATERIALIZED VIEW を参照してください。

1.4.6 複数ソースのパーティション更新​

定義:非同期マテリアライズドビューでは、パーティション変更を追跡するテーブルを複数指定できます。これらのテーブルのいずれかのデータが変更された場合、マテリアライズドビューは全件更新ではなくパーティション更新を行います。

制約:

  • INNER JOIN または UNION(UNION ALL を含む)に基づくマテリアライズドビューのみをサポートします。

  • マテリアライズドビューで UNION を使用する場合、結合に参加する各部分がパーティション変更追跡(PCT)をサポートしている必要があります。たとえば、定義が q1 union all q2 の場合、q1 と q2 のそれぞれでマテリアライズドビューを作成したときにパーティション更新をサポートし、導出されるパーティション列の順序が一致している必要があります。

  • 複数の PCT テーブル間でパーティションの粒度を揃える必要があります。

    許可される例:

    Partitions of base table t1: [2020-01-01, 2020-01-02), [2020-01-02, 2020-01-03)
    Partitions of base table t2: [2020-01-02, 2020-01-03), [2020-01-03, 2020-01-04)

    複数のベーステーブルのパーティションは完全には一致していませんが、重複していません。

    許可されない例:

    Partitions of base table t1: [2020-01-01, 2020-01-03), [2020-01-03, 2020-01-05)
    Partitions of base table t2: [2020-01-01, 2020-01-02), [2020-01-03, 2020-01-05)

    [2020-01-01, 2020-01-03) と [2020-01-01, 2020-01-02) は重複していますが、一致していません。

1.5 SQL 定義に関する注意事項​

非同期マテリアライズドビューは内部ビュー(View)に基づいて作成できますが、外部データソースのビューに基づく作成には対応していません。

次の点に注意してください。

  • マテリアライズドビューが依存する内部ビューを変更または再構築すると、非同期マテリアライズドビューのデータとベーステーブルのデータが一致しなくなります。この場合、マテリアライズドビューのデータは残りますが、透過的なクエリ書き換えには使用できません。
  • 非同期マテリアライズドビューが依存するパーティション追跡テーブルや列、またはそのスキーマに影響する構造変更が行われると、マテリアライズドビューの更新は失敗します。
  • 変更が上記の要素に影響しない場合、更新後にマテリアライズドビューを通常どおり使用できます。

2. マテリアライズドビューのクエリ​

4.1.5 以降、外部テーブルに対する履歴スナップショットクエリと Time Travel クエリは、現在のマテリアライズドビューデータを使用する透過的な書き換えの対象外となり、指定したスナップショットが読み取られます。この制限は、現在のデータに対するクエリの書き換えには影響しません。

マテリアライズドビューに対するクエリには、直接クエリと透過的なクエリ書き換えの2つの方法があります。

クエリ方法元のクエリの変更が必要か適用シナリオ
直接クエリはいマテリアライズドビューが存在することが分かっており、その事前計算済み結果を明示的に使用したい場合。
透過的な書き換えいいえユーザーに意識させずにマテリアライズドビューでクエリを高速化したい場合。

2.1 マテリアライズドビューへの直接クエリ​

マテリアライズドビューはテーブルとして扱い、フィルター条件や集計などを適用して直接クエリできます。

マテリアライズドビューの定義:

CREATE MATERIALIZED VIEW mv_5
BUILD IMMEDIATE REFRESH AUTO ON SCHEDULE EVERY 1 hour
DISTRIBUTED BY RANDOM BUCKETS 3
AS
SELECT t1.l_linenumber,
o_custkey,
o_orderdate
FROM (SELECT * FROM lineitem WHERE l_linenumber > 1) t1
LEFT OUTER JOIN orders
ON l_orderkey = o_orderkey;

元のクエリ:

SELECT t1.l_linenumber,
o_custkey,
o_orderdate
FROM (SELECT * FROM lineitem WHERE l_linenumber > 1) t1
LEFT OUTER JOIN orders
ON l_orderkey = o_orderkey
WHERE o_orderdate = '2023-10-18';

マテリアライズドビューに対する同等の直接クエリ(ユーザーが手動で書き換える必要があります):

SELECT
l_linenumber,
o_custkey
FROM mv_5
WHERE l_linenumber > 1 AND o_orderdate = '2023-10-18';

2.2 透過的なクエリ書き換え​

透過的な書き換えとは、ユーザーが手動で変更しなくても、システムが処理中にクエリを自動的に最適化して書き換えることです。Doris の非同期マテリアライズドビューは、SPJG(SELECT-PROJECT-JOIN-GROUP-BY)パターンに基づく透過的な書き換えアルゴリズムを採用しています。このアルゴリズムは SQL の構造情報を分析して適切なマテリアライズドビューを自動的に見つけ、クエリに応答する最適な結果を選択します。

次の表は、Doris がサポートする透過的な書き換え機能をまとめたものです。

書き換え機能適用シナリオ
述語補完クエリとマテリアライズドビューの WHERE 条件が完全には一致しない場合。
JOIN 書き換えクエリとマテリアライズドビューが、同じテーブルを同じ JOIN タイプで使用する場合。
JOIN 導出クエリとマテリアライズドビューの JOIN タイプが異なっていても、マテリアライズドビューが十分なデータを提供できる場合。
集計の書き換えクエリとマテリアライズドビューのグループ化ディメンションが同じ場合。
集計の書き換え(ロールアップ)マテリアライズドビューのディメンションがクエリのディメンションを包含し、クエリの集計関数をマテリアライズドビューの関数で表現できる場合。
多次元集計の書き換えマテリアライズドビューは GROUPING SETS/CUBE/ROLLUP を使用していないが、クエリに多次元集計がある場合。
パーティション補完の書き換えパーティション分割されたマテリアライズドビューがクエリに必要なデータをすべて提供できないとき、ベーステーブルと UNION ALL で結合する場合。
ネストされたマテリアライズドビューの書き換え別のマテリアライズドビューの上にマテリアライズドビューを構築している場合。
非集計ビューによる集計クエリの書き換えクエリは集計を行うが、マテリアライズドビューは集計を含まず、必要な列をすべて提供できる場合。
ウィンドウ関数の書き換えクエリとマテリアライズドビューの両方にウィンドウ関数があり、その定義が完全に一致する場合。
Limit / TopN の書き換えクエリに ORDER BY または LIMIT があり、マテリアライズドビューが要件を満たす場合。

2.2.1 述語補完​

クエリとマテリアライズドビューの条件が同一である必要はありません。マテリアライズドビューに述語を追加してクエリを表現することで、マテリアライズドビューを最大限に再利用できます。

マテリアライズドビューとクエリの WHERE 条件が AND で結合された式の場合、次の2つのケースが該当します。

ケース 1:クエリの式がマテリアライズドビューの式を含む場合、述語補完を適用できます。

たとえば、クエリが a > 5 AND b > 10 AND c = 7、マテリアライズドビューの条件が a > 5 AND b > 10 の場合、マテリアライズドビューの条件はクエリ条件の一部なので、c = 7 だけを補完します。

ケース 2:クエリの式がマテリアライズドビューの式を完全には含まない場合でも、クエリ条件からマテリアライズドビューの条件を導出できれば(一般に >、<、=、IN などの比較式や範囲式)、述語補完を適用できます。補完後の結果はクエリ条件そのものです。

たとえば、クエリが a > 5 AND b = 10、マテリアライズドビューの条件が a > 1 AND b > 8 の場合、マテリアライズドビューの条件はクエリ条件を包含しており、補完できます。補完後の結果は a > 5 AND b = 10 です。

述語補完の制約:

  • OR で結合された式は述語補完をサポートしていません。書き換えを成功させるには条件が同一である必要があります。
  • LIKE など、比較式でも範囲式でもない式は述語補完をサポートしていません。書き換えを成功させるには条件が同一である必要があります。

例:

マテリアライズドビューの定義:

CREATE MATERIALIZED VIEW mv1
BUILD IMMEDIATE REFRESH AUTO ON SCHEDULE EVERY 1 hour
DISTRIBUTED BY RANDOM BUCKETS 3
AS
SELECT t1.l_linenumber,
o_custkey,
o_orderdate
FROM (SELECT * FROM lineitem WHERE l_linenumber > 1) t1
LEFT OUTER JOIN orders
ON l_orderkey = o_orderkey;

以下のクエリは透過的な書き換えによって同じマテリアライズドビューを使用できます。これにより、書き換え時間とビュー構築のコストを削減できます。

SELECT l_linenumber,
o_custkey,
o_orderdate
FROM lineitem
LEFT OUTER JOIN orders
ON l_orderkey = o_orderkey
WHERE l_linenumber > 2;
SELECT l_linenumber,
o_custkey,
o_orderdate
FROM lineitem
LEFT OUTER JOIN orders
ON l_orderkey = o_orderkey
WHERE l_linenumber > 2 AND o_orderdate = '2023-10-19';

2.2.2 JOIN の書き換え​

適用シナリオ:クエリとマテリアライズドビューが同じテーブルを使用する場合です。WHERE 句は、マテリアライズドビューとクエリのいずれでも、JOIN の入力側または JOIN の外側に配置できます。オプティマイザは、このパターンのクエリに対して透過的な書き換えを試みます。

サポートされる JOIN タイプ:

  • INNER JOIN
  • LEFT OUTER JOIN
  • RIGHT OUTER JOIN
  • FULL OUTER JOIN
  • LEFT SEMI JOIN
  • RIGHT SEMI JOIN
  • LEFT ANTI JOIN
  • RIGHT ANTI JOIN

例:

マテリアライズドビューの定義:

CREATE MATERIALIZED VIEW mv2
BUILD IMMEDIATE REFRESH AUTO ON SCHEDULE EVERY 1 hour
DISTRIBUTED BY RANDOM BUCKETS 3
AS
SELECT t1.l_linenumber,
o_custkey,
o_orderdate
FROM (SELECT * FROM lineitem WHERE l_linenumber > 1) t1
LEFT OUTER JOIN orders
ON l_orderkey = o_orderkey;

次のクエリは透過的に書き換えられます。条件 l_linenumber > 1 を上位に移動し、マテリアライズドビューの事前計算済み結果でクエリを表現できます。マテリアライズドビューを使用すると、JOIN の計算を省けます。

SELECT l_linenumber,
o_custkey
FROM lineitem
LEFT OUTER JOIN orders
ON l_orderkey = o_orderkey
WHERE l_linenumber > 1 AND o_orderdate = '2023-10-18';

2.2.3 JOIN の導出​

クエリとマテリアライズドビューの JOIN タイプが異なる場合でも、マテリアライズドビューがクエリに必要なデータをすべて提供できれば、JOIN の外側で述語を補完して透過的な書き換えを適用できます。

例:

マテリアライズドビューの定義:

CREATE MATERIALIZED VIEW mv3
BUILD IMMEDIATE REFRESH AUTO ON SCHEDULE EVERY 1 hour
DISTRIBUTED BY RANDOM BUCKETS 3
AS
SELECT
l_shipdate, l_suppkey, o_orderdate,
sum(o_totalprice) AS sum_total,
max(o_totalprice) AS max_total,
min(o_totalprice) AS min_total,
count(*) AS count_all,
count(distinct CASE WHEN o_shippriority > 1 AND o_orderkey IN (1, 3) THEN o_custkey ELSE null END) AS bitmap_union_basic
FROM lineitem
LEFT OUTER JOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate
GROUP BY
l_shipdate,
l_suppkey,
o_orderdate;

クエリステートメント:

SELECT
l_shipdate, l_suppkey, o_orderdate,
sum(o_totalprice) AS sum_total,
max(o_totalprice) AS max_total,
min(o_totalprice) AS min_total,
count(*) AS count_all,
count(distinct CASE WHEN o_shippriority > 1 AND o_orderkey IN (1, 3) THEN o_custkey ELSE null END) AS bitmap_union_basic
FROM lineitem
INNER JOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate
WHERE o_orderdate = '2023-10-18' AND l_suppkey = 3
GROUP BY
l_shipdate,
l_suppkey,
o_orderdate;

2.2.4 集計の書き換え​

適用条件:クエリとマテリアライズドビューの定義でグループ化ディメンションが同じであり、クエリの集計関数をマテリアライズドビューの集計関数で表現できることです。

例:

マテリアライズドビューの定義:

CREATE MATERIALIZED VIEW mv4
BUILD IMMEDIATE REFRESH AUTO ON SCHEDULE EVERY 1 hour
DISTRIBUTED BY RANDOM BUCKETS 3
AS
SELECT
o_shippriority, o_comment,
count(distinct CASE WHEN o_shippriority > 1 AND o_orderkey IN (1, 3) THEN o_custkey ELSE null END) AS cnt_1,
count(distinct CASE WHEN O_SHIPPRIORITY > 2 AND o_orderkey IN (2) THEN o_custkey ELSE null END) AS cnt_2,
sum(o_totalprice),
max(o_totalprice),
min(o_totalprice),
count(*)
FROM orders
GROUP BY
o_shippriority,
o_comment;

次のクエリは透過的に書き換えられます。集計ディメンションが同じで、マテリアライズドビューの o_shippriority フィールドを結果のフィルタリングに使用でき、GROUP BY のディメンションと集計関数の両方をマテリアライズドビューで書き換えられます。集計済みマテリアライズドビューを使用すると、集計計算を削減できます。

SELECT
o_shippriority, o_comment,
count(distinct CASE WHEN o_shippriority > 1 AND o_orderkey IN (1, 3) THEN o_custkey ELSE null END) AS cnt_1,
count(distinct CASE WHEN O_SHIPPRIORITY > 2 AND o_orderkey IN (2) THEN o_custkey ELSE null END) AS cnt_2,
sum(o_totalprice),
max(o_totalprice),
min(o_totalprice),
count(*)
FROM orders
WHERE o_shippriority IN (1, 2)
GROUP BY
o_shippriority,
o_comment;

2.2.5 集計の書き換え(ロールアップ)​

集計ディメンションが同一でなくても、以下の要件を満たせば書き換えを適用できます。

  • マテリアライズドビューの GROUP BY ディメンションが、クエリの GROUP BY ディメンションを包含すること。クエリに GROUP BY がなくてもかまいません。
  • クエリの集計関数を、マテリアライズドビューの集計関数で表現できること。

例:

マテリアライズドビューの定義:

CREATE MATERIALIZED VIEW mv5
BUILD IMMEDIATE REFRESH AUTO ON SCHEDULE EVERY 1 hour
DISTRIBUTED BY RANDOM BUCKETS 3
AS
SELECT
l_shipdate, o_orderdate, l_partkey, l_suppkey,
sum(o_totalprice) AS sum_total,
max(o_totalprice) AS max_total,
min(o_totalprice) AS min_total,
count(*) AS count_all,
bitmap_union(to_bitmap(CASE WHEN o_shippriority > 1 AND o_orderkey IN (1, 3) THEN o_custkey ELSE null END)) AS bitmap_union_basic
FROM lineitem
LEFT OUTER JOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate
GROUP BY
l_shipdate,
o_orderdate,
l_partkey,
l_suppkey;

次のクエリは透過的に書き換えられます。マテリアライズドビューのディメンションがクエリのディメンションを包含するため、クエリはマテリアライズドビューの SELECT にある関数を使ったロールアップを試みます。たとえば、マテリアライズドビューの bitmap_union は最終的に bitmap_union_count にロールアップされ、クエリの count(distinct) と意味が一致します。

集計のロールアップにより、同じマテリアライズドビューを複数のクエリで再利用でき、構築コストを削減できます。

SELECT
l_shipdate, l_suppkey,
sum(o_totalprice) AS sum_total,
max(o_totalprice) AS max_total,
min(o_totalprice) AS min_total,
count(*) AS count_all,
count(distinct CASE WHEN o_shippriority > 1 AND o_orderkey IN (1, 3) THEN o_custkey ELSE null END) AS bitmap_union_basic
FROM lineitem
LEFT OUTER JOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate
WHERE o_orderdate = '2023-10-18' AND l_partkey = 3
GROUP BY
l_shipdate,
l_suppkey;

サポートされるロールアップ集計関数の一覧:

クエリ内の関数マテリアライズドビュー内の関数ロールアップ後の関数
maxmaxmax
minminmin
sumsumsum
countcountsum
count(distinct)bitmap_unionbitmap_union_count
bitmap_unionbitmap_unionbitmap_union
bitmap_union_countbitmap_unionbitmap_union_count
hll_union_agg, approx_count_distinct, hll_cardinalityhll_union or hll_raw_agghll_union_agg
any_valueany_value or a column referenced by any_value after SELECTany_value

2.2.6 多次元集計の書き換え​

透過的な書き換えは多次元集計をサポートします。マテリアライズドビューが GROUPING SETS/CUBE/ROLLUP を使用せず、クエリに多次元集計があり、マテリアライズドビューの GROUP BY 列がクエリの多次元集計で参照されるすべての列を含む場合に適用できます。

例:

マテリアライズドビューの定義:

CREATE MATERIALIZED VIEW mv5_1
BUILD IMMEDIATE REFRESH AUTO ON SCHEDULE EVERY 1 hour
DISTRIBUTED BY RANDOM BUCKETS 3
AS
SELECT o_orderstatus, o_orderdate, o_orderpriority,
sum(o_totalprice) AS sum_total,
max(o_totalprice) AS max_total,
min(o_totalprice) AS min_total,
count(*) AS count_all
FROM orders
GROUP BY
o_orderstatus, o_orderdate, o_orderpriority;

次のクエリはマテリアライズドビューを使用でき、集計結果を再利用して計算を省けます。

SELECT o_orderstatus, o_orderdate, o_orderpriority,
sum(o_totalprice),
max(o_totalprice),
min(o_totalprice),
count(*)
FROM orders
GROUP BY
GROUPING SETS ((o_orderstatus, o_orderdate), (o_orderpriority), (o_orderstatus), ());

2.2.7 パーティション補完の書き換え​

適用シナリオ:パーティション分割されたマテリアライズドビューがクエリに必要なデータをすべて提供できない場合、元のベーステーブルのデータとマテリアライズドビューのデータを UNION ALL で結合し、最終結果とします。

例:

マテリアライズドビューの定義:

CREATE MATERIALIZED VIEW mv7
BUILD IMMEDIATE REFRESH AUTO ON MANUAL
PARTITION BY (l_shipdate)
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT l_shipdate, o_orderdate, l_partkey,
l_suppkey, sum(o_totalprice) AS sum_total
FROM lineitem
LEFT JOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate
GROUP BY
l_shipdate,
o_orderdate,
l_partkey,
l_suppkey;

ベーステーブルに新しいパーティション 2023-10-21 が追加され、マテリアライズドビューがまだ更新されていない場合でも、マテリアライズドビューと元のテーブルを UNION ALL で結合して結果を返せます。

INSERT INTO lineitem VALUES
(1, 2, 3, 4, 5.5, 6.5, 7.5, 8.5, 'o', 'k', '2023-10-21', '2023-10-21', '2023-10-21', 'a', 'b', 'yyyyyyyyy');

クエリステートメント:

SELECT l_shipdate, o_orderdate, l_partkey, l_suppkey, sum(o_totalprice) AS sum_total
FROM lineitem
LEFT JOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate
GROUP BY
l_shipdate,
o_orderdate,
l_partkey,
l_suppkey;

クエリは事前計算された結果の一部を使用でき、対応する計算を省けます。

書き換え後の結果のイメージ:

SELECT *
FROM mv7
UNION ALL
SELECT t1.l_shipdate, o_orderdate, t1.l_partkey, t1.l_suppkey, sum(o_totalprice) AS sum_total
FROM (SELECT * FROM lineitem WHERE l_shipdate = '2023-10-21') t1
LEFT JOIN orders ON t1.l_orderkey = orders.o_orderkey AND t1.l_shipdate = o_orderdate
GROUP BY
t1.l_shipdate,
o_orderdate,
t1.l_partkey,
t1.l_suppkey;
注意

パーティション補完は現在サポートされていますが、条件を伴う UNION ALL 補完はまだサポートされていません。

たとえば、マテリアライズドビューをフィルター条件 WHERE l_shipdate > '2023-10-19' で構築し、クエリが WHERE l_shipdate > '2023-10-18' の場合、現時点では UNION ALL による補完はできません。今後対応する予定です。

注記

バージョン 3.1.0 以降、パーティション補完の書き換え機能は、内部テーブル、Hive、Iceberg、Paimon のパーティション分割テーブルをサポートします。パーティション補完の書き換えは、これらのいずれかのパーティション分割テーブル上にマテリアライズドビューを構築した場合にのみトリガーされます。

2.2.8 ネストされたマテリアライズドビューの書き換え​

定義:マテリアライズドビューの定義 SQL で別のマテリアライズドビューを使用できます。これをネストされたマテリアライズドビューと呼びます。ネストできる階層数は理論上無制限です。ネストされたマテリアライズドビューには直接クエリでき、透過的な書き換えにも使用できます。

適用シナリオ:データモデリングや複雑なクエリでよく使用します。単一のマテリアライズドビューでは透過的な書き換えができない場合、複雑なクエリを分割し、ネストされたマテリアライズドビューを構築できます。

例:

内側のマテリアライズドビュー mv8_0_inner_mv を作成します。

CREATE MATERIALIZED VIEW mv8_0_inner_mv
BUILD IMMEDIATE REFRESH COMPLETE ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT
l_linenumber,
o_custkey,
o_orderkey,
o_orderstatus,
l_partkey,
l_suppkey,
l_orderkey
FROM lineitem
INNER JOIN orders ON lineitem.l_orderkey = orders.o_orderkey;

外側のマテリアライズドビュー mv8_0 を作成します。

CREATE MATERIALIZED VIEW mv8_0
BUILD IMMEDIATE REFRESH COMPLETE ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT
l_linenumber,
o_custkey,
o_orderkey,
o_orderstatus,
l_partkey,
l_suppkey,
l_orderkey,
ps_availqty
FROM mv8_0_inner_mv
INNER JOIN partsupp ON l_partkey = ps_partkey AND l_suppkey = ps_suppkey;

次のクエリでは mv8_0_inner_mv と mv8_0 の両方で書き換えが成功し、最終的にコストモデルが mv8_0 を選択します。

SELECT lineitem.l_linenumber
FROM lineitem
INNER JOIN orders ON l_orderkey = o_orderkey
INNER JOIN partsupp ON l_partkey = ps_partkey AND l_suppkey = ps_suppkey
WHERE o_orderstatus = 'o';
注意
  • マテリアライズドビューのネストが深いほど、透過的な書き換えに時間がかかります。ネストの深さは3階層以内を推奨します。
  • ネストされたマテリアライズドビューの透過的な書き換えは、デフォルトで無効です。有効にする方法は 3.11 関連設定 を参照してください。

2.2.9 集計クエリが非集計マテリアライズドビューを使用する場合​

クエリが集計クエリで、マテリアライズドビューに集計が含まれない場合でも、マテリアライズドビューがクエリで使用する列をすべて提供できれば、書き換えを適用できます。たとえば、クエリが先に JOIN を行い、その後 GROUP BY で集計する場合、JOIN を含むマテリアライズドビューを使用すると効果的です。

CREATE MATERIALIZED VIEW mv10_0
BUILD IMMEDIATE REFRESH AUTO ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT l_shipdate, o_orderdate, l_partkey,
l_suppkey, o_totalprice
FROM lineitem
LEFT JOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate;

次のクエリは mv10_0 を使用でき、lineitem JOIN orders の計算を省けます。

SELECT l_shipdate, o_orderdate, l_partkey,
l_suppkey, sum(o_totalprice) AS sum_total
FROM lineitem
LEFT JOIN orders ON lineitem.l_orderkey = orders.o_orderkey AND l_shipdate = o_orderdate
GROUP BY
l_shipdate,
o_orderdate,
l_partkey,
l_suppkey;

2.2.10 ウィンドウ関数の書き換え​

クエリとマテリアライズドビューの両方にウィンドウ関数があり、その定義が完全に一致する場合、透過的な書き換えを適用できます。ウィンドウ関数の書き換えでは、マテリアライズドビュー内の事前計算済み結果を再利用するため、複雑なウィンドウ計算を伴うクエリの性能が大幅に向上します。現在、すべてのウィンドウ関数が透過的な書き換えをサポートしています。

例 1:

CREATE MATERIALIZED VIEW mv11_0
BUILD IMMEDIATE REFRESH AUTO ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT *
FROM (
SELECT
o_orderkey,
FIRST_VALUE(o_custkey) OVER (
PARTITION BY o_orderdate
ORDER BY o_totalprice NULLS LAST
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS first_value,
RANK() OVER (
PARTITION BY o_orderdate, o_orderstatus
ORDER BY o_totalprice NULLS LAST
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS rank_value
FROM orders
) t
WHERE o_orderkey > 1;

次のクエリは mv11_0 を使用でき、ウィンドウ関数の計算を省けます。クエリ条件 o_orderkey > 2 がマテリアライズドビューと異なっていても、書き換えは成功します。

SELECT *
FROM (
SELECT
o_orderkey,
FIRST_VALUE(o_custkey) OVER (
PARTITION BY o_orderdate
ORDER BY o_totalprice NULLS LAST
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS first_value,
RANK() OVER (
PARTITION BY o_orderdate, o_orderstatus
ORDER BY o_totalprice NULLS LAST
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS rank_value
FROM orders
) t
WHERE o_orderkey > 2;

例 2:

CREATE MATERIALIZED VIEW mv11_1
BUILD IMMEDIATE REFRESH AUTO ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT
o_orderkey,
o_orderdate,
FIRST_VALUE(o_custkey) OVER (
PARTITION BY o_orderdate
ORDER BY o_totalprice NULLS LAST
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS first_value,
RANK() OVER (
PARTITION BY o_orderdate, o_orderstatus
ORDER BY o_totalprice NULLS LAST
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS rank_value
FROM orders
WHERE o_orderdate > '2023-12-09';

次のクエリは mv11_1 を使用でき、ウィンドウ関数の計算を省けます。o_orderdate はウィンドウ関数の PARTITION BY フィールドなので、クエリ条件 o_orderdate > '2023-12-10' がウィンドウ関数の実行前に評価されても、透過的な書き換えを適用できます。

SELECT
o_orderdate,
FIRST_VALUE(o_custkey) OVER (
PARTITION BY o_orderdate
ORDER BY o_totalprice NULLS LAST
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS first_value,
RANK() OVER (
PARTITION BY o_orderdate, o_orderstatus
ORDER BY o_totalprice NULLS LAST
RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS rank_value
FROM orders
WHERE o_orderdate > '2023-12-10';
ヒント

この例では単一のテーブルを使用していますが、ウィンドウ関数の書き換えは複数テーブルの JOIN にも適用できます。

2.2.11 Limit と TopN の書き換え​

クエリに ORDER BY または LIMIT 句がある場合(つまり Top-N クエリの場合)、マテリアライズドビューがクエリの ORDER BY と LIMIT の要件を満たすだけのデータを提供できれば、オプティマイザはマテリアライズドビューを使って透過的に書き換えられます。これにより、一般的な Top-N 分析クエリを大幅に高速化できます。

書き換え条件:

確認項目検証ルール
ORDER BYクエリの ORDER BY 句が、マテリアライズドビューの ORDER BY 句と互換性があるか、同一である必要があります。
LIMITマテリアライズドビューに LIMIT がない場合、LIMIT を持つ任意のクエリで書き換えを試行できます。
マテリアライズドビューに LIMIT N がある場合、クエリの LIMIT M は M <= N を満たす必要があります。
マテリアライズドビューに LIMIT N OFFSET L がある場合、クエリの LIMIT M OFFSET O は O >= L かつ M + O <= N + L を満たす必要があります。
WHERE 条件マテリアライズドビューとクエリのその他の WHERE 条件は同じである必要があります。

例 1:

CREATE MATERIALIZED VIEW mv11_0
BUILD IMMEDIATE REFRESH AUTO ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT
o_orderdate,
count(o_shippriority),
count(o_comment),
l_orderkey,
count(l_partkey)
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey
LEFT JOIN partsupp ON ps_partkey = l_partkey AND l_suppkey = ps_suppkey
GROUP BY o_orderdate, l_orderkey
LIMIT 8 OFFSET 1;

次のクエリは検証条件を満たし、mv11_0 を使用できます。

SELECT
o_orderdate,
count(o_shippriority),
count(o_comment),
l_orderkey,
count(l_partkey)
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey
LEFT JOIN partsupp ON ps_partkey = l_partkey AND l_suppkey = ps_suppkey
GROUP BY o_orderdate, l_orderkey
LIMIT 4 OFFSET 2;

次のクエリには追加の条件 o_orderdate > '2023-12-08' があるため、mv11_0 を使用できません。mv11_0 マテリアライズドビューにもこの WHERE 条件があれば、使用できます。

SELECT
o_orderdate,
count(o_shippriority),
count(o_comment),
l_orderkey,
count(l_partkey)
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey
LEFT JOIN partsupp ON ps_partkey = l_partkey AND l_suppkey = ps_suppkey
WHERE o_orderdate > '2023-12-08'
GROUP BY o_orderdate, l_orderkey
LIMIT 4 OFFSET 2;

例 2:

CREATE MATERIALIZED VIEW mv11_1
BUILD IMMEDIATE REFRESH AUTO ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
AS
SELECT
o_orderdate,
o_shippriority,
o_comment,
l_orderkey,
l_partkey,
o_orderkey
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey
LEFT JOIN partsupp ON ps_partkey = l_partkey AND l_suppkey = ps_suppkey
WHERE o_orderdate > '2023-12-08'
ORDER BY o_orderkey
LIMIT 4 OFFSET 2;

次のクエリの ORDER BY + LIMIT は TopN に変換されます。このクエリは検証条件を満たし、mv11_1 を使用できます。

SELECT
o_orderdate,
o_shippriority,
o_comment,
l_orderkey,
l_partkey
FROM orders
LEFT JOIN lineitem ON l_orderkey = o_orderkey
LEFT JOIN partsupp ON ps_partkey = l_partkey AND l_suppkey = ps_suppkey
WHERE o_orderdate > '2023-12-08'
ORDER BY o_orderkey
LIMIT 2 OFFSET 3;

2.3 透過的な書き換えの確認(Explain)​

2.3.1 概要表示:EXPLAIN​

マテリアライズドビューの透過的な書き換え処理の概要を確認するには、次を実行します。

EXPLAIN <query_sql>

返される情報(マテリアライズドビューに関連する部分の抜粋):

| MaterializedView                                                              |
| MaterializedViewRewriteSuccessAndChose: |
| Names: mv5 |
| MaterializedViewRewriteSuccessButNotChose: |
| |
| MaterializedViewRewriteFail: |
| Name: mv4 |
| FailSummary: Match mode is invalid, View struct info is invalid |
| Name: mv3 |
| FailSummary: Match mode is invalid, Rewrite compensate predicate by view fail, View struct info is invalid |
| Name: mv1 |
| FailSummary: The columns used by query are not in view, View struct info is invalid |
| Name: mv2 |
| FailSummary: The columns used by query are not in view, View struct info is invalid |

各フィールドの意味:

  • MaterializedViewRewriteSuccessAndChose:透過的な書き換えに成功し、CBO(コストベースオプティマイザ)に選択されたマテリアライズドビュー名の一覧です。
  • MaterializedViewRewriteSuccessButNotChose:透過的な書き換えに成功したものの、最終的に CBO に選択されなかったマテリアライズドビュー名の一覧です。
  • MaterializedViewRewriteFail:透過的な書き換えに失敗したマテリアライズドビューと、その理由の概要です。

2.3.2 詳細表示:EXPLAIN MEMO PLAN​

マテリアライズドビューの候補、書き換え、最終選択の詳細な処理を確認するには、次を実行します。

EXPLAIN MEMO PLAN <query_sql>

3. マテリアライズドビューの保守​

3.1 権限​

操作必要な権限
マテリアライズドビューの削除マテリアライズドビューに対する削除権限(テーブルの削除と同じ)。
マテリアライズドビューの変更マテリアライズドビューに対する変更権限(テーブルの変更と同じ)。
マテリアライズドビューの一時停止/再開/キャンセル/更新マテリアライズドビューに対する作成権限。

3.2 マテリアライズドビューの変更​

3.2.1 マテリアライズドビューのプロパティの変更​

ALTER MATERIALIZED VIEW mv_1
SET(
"grace_period" = "10"
);

3.2.2 マテリアライズドビューのアトミックな置換(名前変更)​

まず、置換先となる新しいマテリアライズドビューを作成します。

CREATE MATERIALIZED VIEW mv9_0
BUILD IMMEDIATE REFRESH COMPLETE ON MANUAL
DISTRIBUTED BY RANDOM BUCKETS 2
PROPERTIES ('replication_num' = '1')
AS
SELECT
l_linenumber,
o_custkey,
o_orderkey,
o_orderstatus,
l_partkey,
l_suppkey,
l_orderkey
FROM lineitem
INNER JOIN orders ON lineitem.l_orderkey = orders.o_orderkey;

mv7 を mv9_0 で置き換え、mv7 を削除します。

ALTER MATERIALIZED VIEW mv7
REPLACE WITH MATERIALIZED VIEW mv9_0
PROPERTIES('swap' = 'false');

3.3 マテリアライズドビューの削除​

DROP MATERIALIZED VIEW mv_1;

詳細は DROP ASYNC MATERIALIZED VIEW を参照してください。

3.4 マテリアライズドビューの作成ステートメントの表示​

SHOW CREATE MATERIALIZED VIEW mv_1;

詳細は SHOW CREATE MATERIALIZED VIEW を参照してください。

3.5 更新の一時停止/有効化/キャンセル​

操作リファレンスドキュメント
マテリアライズドビューの一時停止PAUSE MATERIALIZED VIEW
マテリアライズドビューの有効化RESUME MATERIALIZED VIEW
マテリアライズドビューの更新タスクのキャンセルCANCEL MATERIALIZED VIEW TASK

3.6 マテリアライズドビュー情報のクエリ​

SELECT *
FROM mv_infos('database'='db_name')
WHERE Name = 'mv_name' \G

返される結果の例:

*************************** 1. row ***************************
Id: 139570
Name: mv11
JobName: inner_mtmv_139570
State: NORMAL
SchemaChangeDetail:
RefreshState: SUCCESS
RefreshInfo: BUILD IMMEDIATE REFRESH AUTO ON MANUAL
QuerySql: SELECT l_shipdate, l_orderkey, O_ORDERDATE, count(*)
FROM lineitem
LEFT OUTER JOIN orders on l_orderkey = o_orderkey
GROUP BY l_shipdate, l_orderkey, O_ORDERDATE
EnvInfo: EnvInfo{ctlId='0', dbId='16813'}
MvProperties: {}
MvPartitionInfo: MTMVPartitionInfo{partitionType=FOLLOW_BASE_TABLE, relatedTable=lineitem, relatedCol='l_shipdate', partitionCol='l_shipdate'}
SyncWithBaseTables: 1

主なフィールドの説明:

  • SyncWithBaseTables:マテリアライズドビューのデータがベーステーブルと一致しているかを示します。
    • 完全に構築されたマテリアライズドビューでは、値 1 は透過的な書き換えに使用できることを示します。
    • パーティション単位で増分更新するマテリアライズドビューでは、パーティション単位で判定します。一部のパーティションが使用できなくても、クエリ対象のパーティションが有効なら、透過的な書き換えに使用できます。透過的な書き換えが可能かどうかは、主にクエリで使用するパーティションの SyncWithBaseTables フィールドで決まります。1 は使用可能、0 は使用不可を意味します。
  • JobName:マテリアライズドビューを構築するジョブの名前です。各マテリアライズドビューには1つのジョブがあり、更新のたびに新しいタスクが作成されます。ジョブとタスクの関係は 1:n です。
  • State:値が SCHEMA_CHANGE の場合、ベーステーブルのスキーマが変更されたことを示します。この場合、マテリアライズドビューを透過的な書き換えに使用できません(直接クエリには影響しません)。次回の更新が成功すると、NORMAL に戻ります。
  • SchemaChangeDetail:SCHEMA_CHANGE が発生した理由を示します。
  • RefreshState:マテリアライズドビューの最後のタスクの更新状態です。FAIL の場合は、tasks() コマンドで失敗原因を詳しく調べられます(3.7 更新タスク(TASK)情報のクエリ を参照)。

透過的な書き換えの状態:

  • 正常な状態:現在、マテリアライズドビューを透過的な書き換えに使用できます。
  • 異常/使用不可の状態:マテリアライズドビューを透過的な書き換えに使用できませんが、直接クエリは可能です。

詳細は MV_INFOS を参照してください。

3.7 更新タスク(TASK)情報のクエリ​

各マテリアライズドビューには1つのジョブがあり、更新のたびに新しいタスクが作成されます。ジョブとタスクの関係は 1:n です。マテリアライズドビュー名でタスクの状態を確認するには、次を実行します。

SELECT *
FROM tasks("type"="mv")
WHERE
MvDatabaseName = 'mv_db_name' AND
mvName = 'mv_name'
ORDER BY CreateTime DESC \G

返される結果の例:

*************************** 1. row ***************************
TaskId: 167019363907545
JobId: 139872
JobName: inner_mtmv_139570
MvId: 139570
MvName: mv11
MvDatabaseId: 16813
MvDatabaseName: regression_test_nereids_rules_p0_mv
Status: SUCCESS
ErrorMsg:
CreateTime: 2024-06-21 10:31:43
StartTime: 2024-06-21 10:31:43
FinishTime: 2024-06-21 10:31:45
DurationMs: 2466
TaskContext: {"triggerMode":"SYSTEM","isComplete":false}
RefreshMode: COMPLETE
NeedRefreshPartitions: ["p_20231023_20231024","p_20231019_20231020","p_20231020_20231021","p_20231027_20231028","p_20231030_20231031","p_20231018_20231019","p_20231024_20231025","p_20231021_20231022","p_20231029_20231030","p_20231028_20231029","p_20231025_20231026","p_20231022_20231023","p_20231031_20231101","p_20231016_20231017","p_20231026_20231027"]
CompletedPartitions: ["p_20231023_20231024","p_20231019_20231020","p_20231020_20231021","p_20231027_20231028","p_20231030_20231031","p_20231018_20231019","p_20231024_20231025","p_20231021_20231022","p_20231029_20231030","p_20231028_20231029","p_20231025_20231026","p_20231022_20231023","p_20231031_20231101","p_20231016_20231017","p_20231026_20231027"]
Progress: 100.00% (15/15)
LastQueryId: fe700ca3d6504521-bb522fc9ccf615e3

主なフィールドの説明:

  • NeedRefreshPartitions / CompletedPartitions:このタスクで更新が必要なパーティションと、更新済みのパーティションを示します。
  • Status:FAILED は実行失敗を示します。ErrorMsg で原因を確認するか、LastQueryId を使って Doris のログを検索すると詳細を確認できます。現在、タスクが失敗すると、既存のマテリアライズドビューは使用できなくなります。将来的には、タスクが失敗しても既存のマテリアライズドビューを透過的な書き換えに引き続き使用できるよう変更される予定です。
  • ErrorMsg:失敗の原因を示します。
  • RefreshMode:
    • COMPLETE:全パーティションを更新しました。
    • PARTIAL:一部のパーティションを更新しました。
    • NOT_REFRESH:更新が必要なパーティションはありません。
注記
  • 現在、保存・表示されるタスク数のデフォルトは100です。fe.conf の max_persistence_task_count で変更できます。この数を超えると古いタスクの記録が破棄されます。値が1未満の場合、永続化は行われません。この設定は FE の再起動後に有効になります。
  • マテリアライズドビューの作成時に grace_period プロパティを設定している場合、SyncWithBaseTables が false または 0 でも、状況によっては透過的な書き換えに使用できます。
  • grace_period の単位は秒で、マテリアライズドビューとベーステーブルのデータ間で許容する不一致を示します。
    • 0 に設定:透過的な書き換えを適用するには、マテリアライズドビューのデータがベーステーブルのデータと完全に一致している必要があります。
    • 10 に設定:10秒の遅延を許容し、その間はマテリアライズドビューを透過的な書き換えに使用できます。

詳細は TASKS を参照してください。

3.8 マテリアライズドビューに対応する JOB のクエリ​

SELECT *
FROM jobs("type"="mv")
WHERE Name = "inner_mtmv_75043";

詳細は JOBS を参照してください。

3.9 マテリアライズドビューのパーティション情報のクエリ​

パーティション分割されたマテリアライズドビューでは、SHOW PARTITIONS を使用して SyncWithBaseTables の状態を確認します。

SHOW PARTITIONS FROM mv_name;

返される結果の例:

+-------------+---------------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+-----------+------------+-------------------------+-----------+--------------------+--------------+
| PartitionId | PartitionName | VisibleVersion | VisibleVersionTime | State | PartitionKey | Range | DistributionKey | Buckets | ReplicationNum | StorageMedium | CooldownTime | RemoteStoragePolicy | LastConsistencyCheckTime | DataSize | IsInMemory | ReplicaAllocation | IsMutable | SyncWithBaseTables | UnsyncTables |
+-------------+---------------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+-----------+------------+-------------------------+-----------+--------------------+--------------+
| 140189 | p_20231016_20231017 | 1 | 2024-06-21 10:31:45 | NORMAL | l_shipdate | [types: [DATEV2]; keys: [2023-10-16]; ..types: [DATEV2]; keys: [2023-10-17]; ) | l_orderkey | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 0.000 | false | tag.location.default: 1 | true | true | [] |
| 139995 | p_20231018_20231019 | 2 | 2024-06-21 10:31:44 | NORMAL | l_shipdate | [types: [DATEV2]; keys: [2023-10-18]; ..types: [DATEV2]; keys: [2023-10-19]; ) | l_orderkey | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 880.000 B | false | tag.location.default: 1 | true | true | [] |
| 139898 | p_20231019_20231020 | 2 | 2024-06-21 10:31:43 | NORMAL | l_shipdate | [types: [DATEV2]; keys: [2023-10-19]; ..types: [DATEV2]; keys: [2023-10-20]; ) | l_orderkey | 10 | 1 | HDD | 9999-12-31 23:59:59 | | NULL | 878.000 B | false | tag.location.default: 1 | true | true | [] |
+-------------+---------------------+----------------+---------------------+--------+--------------+--------------------------------------------------------------------------------+-----------------+---------+----------------+---------------+---------------------+---------------------+--------------------------+-----------+------------+-------------------------+-----------+--------------------+--------------+

主に確認するフィールドは SyncWithBaseTables です。true はそのパーティションを透過的な書き換えに使用できること、false は使用できないことを意味します。

詳細は SHOW PARTITIONS を参照してください。

3.10 マテリアライズドビューのスキーマの表示​

詳細は DESCRIBE を参照してください。

3.11.1 セッション変数のスイッチ​

スイッチ説明
SET enable_nereids_planner = true;非同期マテリアライズドビューは新しいオプティマイザでのみサポートされます。透過的な書き換えが有効にならない場合は、このスイッチを有効にしてください。
SET enable_materialized_view_rewrite = true;透過的なクエリ書き換えを有効または無効にします。バージョン 2.1.5 以降はデフォルトで有効です。
SET materialized_view_rewrite_enable_contain_external_table = true;透過的な書き換えに使用するマテリアライズドビューに外部テーブルを含められるかを指定します。デフォルトでは許可されません。マテリアライズドビューの定義 SQL に外部テーブルが含まれ、透過的な書き換えに使用したい場合は、このスイッチを有効にしてください。
SET materialized_view_rewrite_success_candidate_num = 3;書き換えに成功した結果のうち、CBO の候補に含める最大数です。デフォルトは3です。透過的な書き換えが遅い場合は、この値を小さくしてください。
SET enable_materialized_view_union_rewrite = true;パーティション分割されたマテリアライズドビューがクエリに必要なデータをすべて提供できない場合、ベーステーブルとマテリアライズドビューを UNION ALL で結合してクエリに応答することを許可するかを指定します。デフォルトで許可されます。マテリアライズドビューを使用した際にデータの誤りが見つかった場合は、このスイッチを無効にしてください。
SET enable_materialized_view_nest_rewrite = true;ネストされた書き換えを許可するかを指定します。デフォルトでは許可されません。クエリ SQL が複雑で、ネストされたマテリアライズドビューの構築が必要な場合は有効にしてください。
SET materialized_view_relation_mapping_max_count = 8;透過的な書き換え中に許可するリレーションマッピングの最大数です。上限を超えたマッピングは切り捨てられます。リレーションマッピングは通常、自己結合によって生成され、その数は直積になります(たとえば、3つのテーブルから8通りの組み合わせが生じる場合があります)。デフォルトは8です。透過的な書き換えが遅い場合は、この値を小さくしてください。
SET enable_dml_materialized_view_rewrite = true;DML 中に、構造情報に基づくマテリアライズドビューの透過的な書き換えを有効にするかを指定します。デフォルトで有効です。
SET enable_dml_materialized_view_rewrite_when_base_table_unawareness = true;データ変更をリアルタイムで検出できない外部テーブルがマテリアライズドビューに含まれる場合、DML 中に構造情報に基づく透過的な書き換えを有効にするかを指定します。デフォルトで無効です。

3.11.2 fe.conf の設定​

設定項目説明
job_mtmv_task_consumer_thread_num同時に実行できるマテリアライズドビューの更新タスク数を制御します。デフォルトは10で、この数を超えたタスクは保留状態になります。この値を変更した後は FE の再起動が必要です。