Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

ReplacingMergeTree テーブルエンジン

このエンジンは、同じソートキーの値 (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*DateDateTimeDateTime64 のいずれかです。省略可能なパラメータです。

マージ時、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 の詳細ガイドを参照することをお勧めします。

Navigation