ClickHouse 中的物化视图:数据丢失场景
ClickHouse 中的物化视图(MV)类似于在仅追加环境中对 INSERT 操作的触发器。它们用于捕获数据变更,但不支持 UPDATE 或 DELETE。只要遵守规则,MV 运行可靠,但表架构变更可能导致数据丢失。
主要风险:ClickHouse 允许独立于活跃 MV 修改源表和目标表。这与传统 DBMS 不同。
经典工作流程
创建测试表和 MV 以进行演示:
-- Source table
DROP TABLE IF EXISTS test_orders;
CREATE TABLE test_orders (
order_id String,
order_dt Datetime
)
ENGINE = MergeTree
ORDER BY order_id;
-- Target table
DROP TABLE IF EXISTS final_test_orders;
CREATE TABLE final_test_orders (
order_id String,
order_dt Datetime
)
ENGINE = MergeTree
ORDER BY order_id;
-- MV to redirect data
DROP VIEW IF EXISTS mv_final_test_orders;
CREATE MATERIALIZED VIEW mv_final_test_orders
TO default.final_test_orders (
order_id String,
order_dt Datetime
)
AS SELECT order_id, order_dt FROM test_orders;
插入数据:
INSERT INTO test_orders VALUES
('QWE123', '2025-03-01 12:00:00'),
('RTY456', '2025-03-01 13:00:00'),
('XYZ789', '2025-03-01 14:00:00');
查询 SELECT * FROM final_test_orders 将正确返回所有记录。
破坏目标表架构
更改 final_test_orders 中的列类型:
DROP TABLE IF EXISTS final_test_orders;
CREATE TABLE final_test_orders (
order_id UInt64,
order_dt Datetime
)
ENGINE = MergeTree
ORDER BY order_id;
重复向 test_orders 插入数据。MV 将抛出 String 到 UInt64 的转换错误。数据会写入源表,但不会写入目标表。由于块原子性,INSERT 将失败。
ClickHouse 以块的方式插入数据。MV 中的错误会中断整个 INSERT,但部分块可能仍会保留。
忽略 MV 错误
设置 materialized_views_ignore_errors=true 可以抑制 MV 错误:
INSERT INTO test_orders SETTINGS materialized_views_ignore_errors = true VALUES
('QWE123', '2025-03-01 12:00:00'),
('RTY456', '2025-03-01 13:00:00'),
('XYZ789', '2025-03-01 14:00:00');
数据会提交到 test_orders,但 final_test_orders 中什么都不会出现。这是目标表中的可控丢失。
通过系统日志监控错误
使用 system.query_views_log 跟踪 MV 失败:
SELECT event_time, view_name, exception
FROM system.query_views_log
WHERE event_date = today() AND exception_code != 0
ORDER BY event_time DESC
LIMIT 1000;
该查询会返回错误时间戳、MV 名称和异常文本。在生产环境中为这些事件设置告警。
将 materialized_views_ignore_errors=true 与监控结合使用,可以将风险降到最低。
列不匹配导致的无控丢失
MV 使用列名而非位置。缺失的列会用默认值填充,且不会报错。
重命名列:
DROP TABLE IF EXISTS final_test_orders;
CREATE TABLE final_test_orders (
orders String,
order_dt Datetime
)
ENGINE = MergeTree
ORDER BY orders;
向 test_orders 插入数据会成功。在 final_test_orders 中,orders 列将被填充为空字符串——数据悄无声息地丢失。
操作 MV 的建议
- 创建 MV 时检查目标表中的列。
- 部署后测试 MV。
- 避免对有活跃 MV 的表进行架构变更。
- 在
system.query_views_log上实现告警。
关键点:
- MV 是无事务保证的无控 ETL。
- 块插入在出错时存在部分丢失风险。
materialized_views_ignore_errors=true会保留源数据,但需要监控。- 列名不匹配会导致静默失败。
- ClickHouse 文档已警告 MV 风险。
— Editorial Team
暂无评论。