ClickHouse中progress指标含义及全局Join统计重复计数问题问询
ClickHouse
statistics 指标设计意图与全局Join场景的统计逻辑 设计意图
ClickHouse的statistics(对应查询进度中的progress)指标,核心是统计查询全链路中所有节点上被加载到内存参与计算的总行数/总字节数,而非仅统计磁盘原始I/O量。它的作用是反映查询执行过程中实际处理的数据规模,不管数据来源是磁盘、内存临时表还是网络分发的数据集,只要被读取并参与计算,就会被计入统计。
全局Join场景的统计重叠合理性
这种“重复统计”是符合设计逻辑的合理行为,以你给出的GLOBAL JOIN示例为例,执行流程分为两个关键阶段:
- 协调节点预加载右表:协调节点会全量读取右表
t1_48021的所有数据(2行,两个节点各1行),构建内存临时表后分发给所有数据节点; - 数据节点执行Join:每个数据节点读取本地左表
t2_48021_local的1行数据(两个节点共2行),再读取分发过来的右表临时表的2行数据(用于匹配Join)。
上述流程中,右表的2行数据被读取了两次:一次是协调节点从磁盘读取,另一次是每个数据节点从内存临时表读取,加上左表的2行读取量,总读取行数为2(协调节点读右表) + 2(数据节点读左表) + 2(数据节点读临时右表)=6,这就是rows_read=6的原因。
这种统计方式并非“重叠错误”,而是因为指标要覆盖查询执行的所有数据处理环节——无论是初始的磁盘读取,还是后续内存中临时数据的复用读取,都是查询执行过程中实际发生的数据加载操作,属于指标统计的范畴。
示例环境与验证
环境配置:2个节点
本地表创建(所有节点执行)
CREATE TABLE test.t1_48021_local ( `a` UInt64, `b` UInt64 ) ENGINE = MergeTree PARTITION BY a ORDER BY a SETTINGS index_granularity = 8192; CREATE TABLE test.t2_48021_local ( `a` UInt64, `c` UInt64 ) ENGINE = MergeTree PARTITION BY a ORDER BY a SETTINGS index_granularity = 8192;
分布式表创建
CREATE TABLE test.t1_48021 ( `a` UInt64, `b` UInt64 ) ENGINE = Distributed('ch_benchmark', 'test', 't1_48021_local', a); CREATE TABLE test.t2_48021 ( `a` UInt64, `c` UInt64 ) ENGINE = Distributed('ch_benchmark', 'test', 't2_48021_local', a);
数据插入(所有节点执行)
INSERT INTO test.t1_48021_local (a, b) VALUES (1, 1); INSERT INTO test.t2_48021_local (a, c) VALUES (1, 1);
查询语句
select * from t2_48021 GLOBAL JOIN t1_48021 ON t1_48021.a=t2_48021.a FORMAT JSON;
查询结果
{ "meta": [ { "name": "a", "type": "UInt64" }, { "name": "c", "type": "UInt64" }, { "name": "t1_48021.a", "type": "UInt64" }, { "name": "b", "type": "UInt64" } ], "data": [ { "a": 1, "c": 1, "t1_48021.a": 1, "b": 1 }, { "a": 1, "c": 1, "t1_48021.a": 1, "b": 1 }, { "a": 1, "c": 1, "t1_48021.a": 1, "b": 1 }, { "a": 1, "c": 1, "t1_48021.a": 1, "b": 1 } ], "rows": 4, "statistics": { "elapsed": 0.002541948, "rows_read": 6, "bytes_read": 96, "total_cpu_seconds": 0.001452, "io_wait_seconds": 0 } }
内容的提问来源于stack exchange,提问作者slow_mohammud
相关产品推荐
相关产品推荐

