このエンジンは、同じソートキーの値 (PRIMARY KEY ではなく、テーブル定義の ORDER BY セクション) を持つ重複エントリを削除する点で、MergeTreeと異なります。
データの重複排除が行われるのは、マージ時のみです。マージはバックグラウンドでいつ行われるか分からないため、それを前提に計画することはできません。データの一部が未処理のまま残る可能性があります。OPTIMIZE クエリを使って臨時にマージを実行することはできますが、OPTIMIZE クエリでは大量のデータの読み書きが発生するため、これに頼るべきではありません。
したがって、ReplacingMergeTree は容量を節約するためにバックグラウンドで重複データを除去する用途には適していますが、重複が存在しないことを保証するものではありません。
テーブルの作成
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE = ReplacingMergeTree([ver [, is_deleted]])
[PARTITION BY expr]
[ORDER BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[SETTINGS name=value, ...]リクエストパラメーターの説明については、ステートメントの説明を参照してください。
ReplacingMergeTree パラメータ
ver
ver — バージョン番号を表すカラムです。型は UInt*、Date、DateTime、DateTime64 のいずれかです。省略可能なパラメータです。
マージ時、ReplacingMergeTree は同じソートキーを持つすべての行の中から 1 行だけを残します。
verが設定されていない場合は、選択対象内の最後の行が残ります。選択対象とは、マージに参加する一連のパーツに含まれる行の集合です。最も後に作成されたパーツ (最後の insert) が選択対象の最後になります。したがって、重複排除後は、各一意のソートキーについて、直近の insert で追加された最後の行が残ります。verが指定されている場合は、最大のバージョンを持つ行が残ります。複数の行でverが同じ場合は、それらには "verが設定されていない場合" のルールが適用されます。つまり、最も新しく挿入された行が残ります。
例:
-- ver なし - 最後に挿入された行が「勝ち」
CREATE TABLE myFirstReplacingMT
(
`key` Int64,
`someCol` String,
`eventTime` DateTime
)
ENGINE = ReplacingMergeTree
ORDER BY key;
INSERT INTO myFirstReplacingMT Values (1, 'first', '2020-01-01 01:01:01');
INSERT INTO myFirstReplacingMT Values (1, 'second', '2020-01-01 00:00:00');
SELECT * FROM myFirstReplacingMT FINAL;
┌is_deleted
is_deleted — マージ時に、この行のデータが state を表すのか、削除対象なのかを判定するために使用されるカラム名です。1 は "deleted" 行、0 は "state" 行です。
カラムのデータ型 — UInt8。
例:
-- ver と is_deleted を使用
CREATE OR REPLACE TABLE myThirdReplacingMT
(
`key` Int64,
`someCol` String,
`eventTime` DateTime,
`is_deleted` UInt8
)
ENGINE = ReplacingMergeTree(eventTime, is_deleted)
ORDER BY key
SETTINGS allow_experimental_replacing_merge_with_cleanup = 1;
INSERT INTO myThirdReplacingMT Values (1, 'first', '2020-01-01 01:01:01', 0);
INSERT INTO myThirdReplacingMT Values (1, 'first', '2020-01-01 01:01:01', 1);
select * from myThirdReplacingMT final;
0 rows in set. Elapsed: 0.003 sec.
-- is_deleted で行を削除
OPTIMIZE TABLE myThirdReplacingMT FINAL CLEANUP;
INSERT INTO myThirdReplacingMT Values (1, 'first', '2020-01-01 00:00:00', 0);
select * from myThirdReplacingMT final;
┌クエリ句
ReplacingMergeTree テーブルの作成時には、MergeTree テーブルの作成時と同じ 句 が必要です。
テーブル作成の非推奨の方法
CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2],
...
) ENGINE [=] ReplacingMergeTree(date-column [, sampling_expression], (primary, key), index_granularity, [ver])ver を除くすべてのパラメータは、MergeTree と同じ意味を持ちます。
ver- バージョンを格納するカラム。省略可能なパラメータです。詳細は上記を参照してください。
クエリ時の重複排除 & FINAL
マージ時には、ReplacingMergeTree が重複する行を識別し、テーブル作成時に指定した ORDER BY カラムの値を一意の識別子として、最も大きいバージョンだけを保持します。ただし、これで保証されるのはあくまで結果整合性のみであり、行が確実に重複排除されるわけではないため、これに依存すべきではありません。そのため、更新行や削除行もクエリ時に考慮されることで、クエリ結果が不正確になる可能性があります。
正しい結果を得るには、バックグラウンドマージに加えて、クエリ時の重複排除と削除行の除去を行う必要があります。これは FINAL 演算子を使って実現できます。たとえば、次の例を見てみましょう。
CREATE TABLE rmt_example
(
`number` UInt16
)
ENGINE = ReplacingMergeTree
ORDER BY number
INSERT INTO rmt_example SELECT floor(randUniform(0, 100)) AS number
FROM numbers(1000000000)
0 rows in set. Elapsed: 19.958 sec. Processed 1.00 billion rows, 8.00 GB (50.11 million rows/s., 400.84 MB/s.)FINAL を使用せずにクエリすると、件数が正しくなりません (実際の結果はマージの状況によって異なります) :
SELECT count()
FROM rmt_example
┌FINAL を追加すると、正しい結果になります:
SELECT count()
FROM rmt_example
FINAL
┌FINAL の詳細や、そのパフォーマンスを最適化する方法については、ReplacingMergeTree の詳細ガイドを参照することをお勧めします。