在工作中遇到了Clickhouse distributed 分布式聚合查詢,二次聚合問題:
全局表的分布鍵值取cityHash64進行分片,相同的target_value 被寫入同一個分片中,這樣對target_value 進行聚合操作,
SQL語句應該分別在每個分片進行查詢(SQL根據全局表的分布鍵值下推),然后把各個分片的聚合結果傳輸到SQL下發節點,直接返回結果:
1)SQL下發后,分片將SQL中的全局表轉換為本地表;
2)直接運行對自己分片的本地表進行聚合查詢;
3)將每個分片運行結果傳輸到SQL下發節點,返回給客戶端;
但是,在實際使用中,並未出現希望的場景。
查看了SQL的執行計划得知:
1)SQL下發后,分片將SQL中的全局表轉換為本地表;
2)每個分片將where條件的結果分別查出;
3)每個分片,將查出的中間數據,傳輸到SQL下發節點;
4)由下發節點來進行中間數據的聚合操作,得出SQL最終結果集,返回給客戶端;
1、表結構如下
----全局表
create table test_all
(
target_type String,
target_value String,
cnd_type String,
cnd_value String,
target_time DateTime
) ENGINE= Distributed('ch_name','test_db','test_local',cityHash64(target_value ));
----本地表
create table test_local
(
target_type String,
target_value String,
cnd_type String,
cnd_value String,
target_time DateTime
) ENGINE= MergeTree
Partition by toDate(target_time)
order by (target_value ,cnd_value );
2、SQL如下
select
target_value ,target_type,cnd_value ,cnd_type ,count() matchCount
from test_all where toDate(target_time) >=toDate('2021-05-09') and toDate(target_time) <=toDate('2021-06-09')
group by target_value ,target_type,cnd_value ,cnd_type
having matchCount>7;
時間范圍內數據總量為1.1億條,經過篩選與排序后的數據油7千萬條,運行時間50-60s之間。
如果換成本地表,則需要SQL運行7s左右:
select
target_value ,target_type,cnd_value ,cnd_type ,count() matchCount
from test_all where toDate(target_time) >=toDate('2021-05-09') and toDate(target_time) <=toDate('2021-06-09')
group by target_value ,target_type,cnd_value ,cnd_type
having matchCount>7;
3、問題解決
1)在分布式(DistributedMergeTree)表中用target_value 做分片鍵;
2)在分片表(也叫本地表)中用target_value 做order by
3)然后設置參數distributed_group_by_no_merge = 1
這個參數(默認為0,表示默認功能關閉)含義就是本地表做完聚合后,不再在分布式表中聚合所有數據。因此需要確保相同的target_value 值出現在同一個分片上(步驟1確保了這一點)。這樣在每個分片上做group by之后,在分布式表做數據匯總即可。從而提升了查詢性能。
4、優化后SQL
select
target_value ,target_type,cnd_value ,cnd_type ,count() matchCount
from test_local where toDate(target_time) >=toDate('2021-05-09') and toDate(target_time) <=toDate('2021-06-09')
group by target_value ,target_type,cnd_value ,cnd_type
having matchCount>7
settings distributed_group_by_no_merge = 1;
運行時間由原來的50-60s,將為17s左右。