Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

ReplacingMergeTree 表引擎

该引擎与 MergeTree 的不同之处在于,它会删除具有相同排序键值 (ORDER BY 部分,而不是 PRIMARY KEY) 的重复条目。

数据去重只会在合并期间发生。合并会在后台于未知时间执行,因此你无法提前规划。部分数据可能仍未处理。虽然你可以使用 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 会在所有排序键相同的行中只保留一行:

  • 如果未设置 ver,则保留选集中最后一行。选集是指参与合并的一组 parts 中的一组行。最近创建的 part (即最后一次 insert) 会是选集中的最后一个。因此,去重后,对于每个唯一的排序键,都会保留最近一次 insert 中的最后一行。
  • 如果指定了 ver,则保留版本号最大的一行。如果多行的 ver 相同,则对这些行应用“未指定 ver”时的规则,也就是说,会保留最近 insert 的那一行。

示例:

-- 不带 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 — 合并期间使用的列名,用于确定该行中的数据表示状态还是应被删除;1 表示“已删除”行,0 表示“状态”行。

列数据类型 — 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 的更多信息,包括如何优化 FINAL 的性能,建议阅读我们的ReplacingMergeTree 详细指南

Navigation