返回首页

ClickHouse 中的 MV:数据丢失和控制

本文分析了在更改表结构时 materialized views ClickHouse 中数据丢失的机制。描述了块插入、ignore_errors 设置以及通过 system.query_views_log 进行监控。为稳定管道提供推荐。

MV ClickHouse 中的数据丢失:如何保护自己
Advertisement 728x90

ClickHouse 中的物化视图:数据丢失场景

ClickHouse 中的物化视图(MV)类似于在仅追加环境中对 INSERT 操作的触发器。它们用于捕获数据变更,但不支持 UPDATE 或 DELETE。只要遵守规则,MV 运行可靠,但表架构变更可能导致数据丢失。

主要风险:ClickHouse 允许独立于活跃 MV 修改源表和目标表。这与传统 DBMS 不同。

经典工作流程

创建测试表和 MV 以进行演示:

Google AdInline article slot
-- 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 中的列类型:

Google AdInline article slot
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 错误:

Google AdInline article slot
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

Advertisement 728x90

继续阅读