clickhouse的bitmap表優化,從50s優化到1s的記錄


背景:

服務器個數:ck小集群4台

單台服務器內存:256G

CPU:48核

bitmap存儲結構,一條數據大概在2M左右

 

表的結構如下:

CREATE TABLE yiche_index.dms_pds_user_dvid_interest_bitmap
(
    `dt` LowCardinality(String) COMMENT '日期',
    `dim_type` LowCardinality(String) COMMENT '維度類型',
    `dim_id` LowCardinality(String) COMMENT '維度值',
    `devid_bmp` AggregateFunction(groupBitmap, UInt32) COMMENT '明細'
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/yiche_index/dms_pds_user_dvid_interest_bitmap', '{replica}')
PARTITION BY toYYYYMMDD(toDate(dt))
PRIMARY KEY (dim_type, dim_id)
ORDER BY (dim_type, dim_id)
SETTINGS index_granularity = 8192

其中的字段devid_bmp存儲的是設備ID明細;

sql如下:

select bitmapCardinality (groupBitmapOrState(devid_bmp)) from ( select devid_bmp from dms_pds_user_dvid_interest_bitmap_all prewhere dt >= '2021-01-01' and dt <= '2021-03-31' and dim_id = '奧迪' and dim_type = '3' );

當前的操作,查詢需要消耗50s+ , 在Grafana上監控發現,瓶頸在IO

 

分析查詢慢的原因:

首先要了解下索引的查詢過程:

假如我的bitmap表總行數是9999行 ,但是建表指定索引粒度是:index_granularity = 8192 , 那么clickhouse就會根據粒度來划分存儲區間(primary.idx)

也就是說,索引的主鍵1~8192是在一個索引區間內,其他的主鍵在另一個索引區間內

有了這個索引區間的划分之后,索引的查詢查詢過程就大致分成如下幾步:

1、where dim_id=789 會分成一個閉區間:[789 , 789]

2、使用上一步查詢的dim_id划分出的區間與生成的索引區間做交集:[789 , 789] ∩ {[1 , 8192] , [8192 , 9999]}

3、第一步交集處理后,發現索引區間的[1 , 8192]是包含[789 , 789]

到這一步就可以定位到為啥上面的sql慢了,直接背景介紹時候說過,一條bitmap數據大小是2M,但是索引區間划分是8192

也就是說我查詢一天的數據,會產生:2M*8192條記錄,這些記錄是在本地表(查詢的是分布式表),在計算的時候要產生密集的IO;

如果查詢的是3個月時間,那么產生的IO粗略看就是:2M*8192*90天

所以要優化也非常簡單:我們bitmap表的特點是:條數少,但每條都很大(2M),因此減小索引間隔粒度大小即可

比如將索引間隔粒度改變為4:SETTINGS index_granularity = 4

重寫灌入數據后再次查詢,同等條件,同等結果。本次查詢只需要1s

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM