Clickhouse使用FINAL修饰符时跳数索引无法生效问题排查
ReplacingMergeTree使用FINAL后跳数索引失效的原因
在ClickHouse 22.3.15.33版本中,当对ReplacingMergeTree表使用FINAL修饰符时跳数索引无法生效,核心原因在于FINAL的执行逻辑与跳数索引的设计目标存在冲突:
1. FINAL的执行机制
ReplacingMergeTree的去重逻辑默认由后台异步合并任务完成,而FINAL会强制查询时实时执行全分区的去重合并——它需要读取分区内所有符合主键范围的行,再在内存中根据ORDER BY定义的顺序和版本字段(若指定),保留每个主键组的最新版本行。
2. 跳数索引的适用限制
跳数索引的作用是快速识别并跳过完全不满足过滤条件的数据块,以此减少扫描的数据量。但FINAL要求必须处理分区内所有可能包含目标主键的行(哪怕部分块看似不满足过滤条件,也可能存在需要参与去重的最新版本行),因此ClickHouse无法提前使用跳数索引跳过任何数据块,只能全量扫描相关分区后再执行去重。
验证示例对比
未使用FINAL的查询(索引生效)
EXPLAIN INDEXES=1 SELECT COUNT(*) FROM mytable WHERE created_date='2022-10-05' and status_id=123;
此查询无需实时去重,ClickHouse可通过跳数索引直接排除不包含status_id=123和created_date='2022-10-05'的数据块,仅扫描符合条件的块。
使用FINAL的查询(索引失效)
EXPLAIN INDEXES=1 SELECT COUNT(*) FROM mytable FINAL WHERE created_date='2022-10-05' and status_id=123;
此查询需要先扫描分区内所有数据块,执行去重后再应用过滤条件,因此跳数索引无法发挥作用。
替代方案
若需同时利用跳数索引和实现去重,可将过滤逻辑与FINAL拆分为子查询:
SELECT COUNT(*) FROM ( SELECT * FROM mytable WHERE created_date='2022-10-05' and status_id=123 FINAL ) AS t;
内层查询先通过WHERE条件利用跳数索引过滤数据块,再对过滤后的结果执行FINAL去重,既能减少扫描的数据量,又能实现去重需求。
内容的提问来源于stack exchange,提问作者Hoptical
相关产品推荐
相关产品推荐

