ClickHouse 高級(五)數據一致性(重點)


查詢 CK 手冊發現,即便對數據一致性支持最好的 Mergetree,也只是 保證最終一致性:

1 准備測試表和數據

(1)創建表 
CREATE TABLE test_a(
 user_id UInt64,
 score String,
 deleted UInt8 DEFAULT 0,
 create_time DateTime DEFAULT toDateTime(0)
)ENGINE= ReplacingMergeTree(create_time)
ORDER BY user_id;
其中:
user_id 是數據去重更新的標識;
create_time 是版本號字段,每組數據中 create_time 最大的一行表示最新的數據;
deleted 是自定的一個標記位,比如 0 代表未刪除,1 代表刪除數據。
(2)寫入 1000 萬 測試數據 
INSERT INTO TABLE test_a(user_id,score)
WITH(
 SELECT ['A','B','C','D','E','F','G']
)AS dict
SELECT number AS user_id, dict[number%7+1] FROM numbers(10000000);
(3)修改前 50 萬 行數據,修改內容包括 name 字段和 create_time 版本號字段 
INSERT INTO TABLE test_a(user_id,score,create_time)
WITH(
 SELECT ['AA','BB','CC','DD','EE','FF','GG']
)AS dict
SELECT number AS user_id, dict[number%7+1], now() AS create_time FROM 
numbers(500000);
(4)統計總數 
SELECT COUNT() FROM test_a;
10500000
還未觸發分區合並,所以還未去重。

2 手動 OPTIMIZE

在寫入數據后,立刻執行 OPTIMIZE 強制觸發新寫入分區的合並動作。 
OPTIMIZE TABLE test_a FINAL;
語法:OPTIMIZE TABLE [db.]name [ON CLUSTER cluster] [PARTITION partition | 
PARTITION ID 'partition_id'] [FINAL] [DEDUPLICATE [BY expression]]

3 通過 Group by 去重

(1)執行去重的查詢 
SELECT
 user_id ,
 argMax(score, create_time) AS score, 
 argMax(deleted, create_time) AS deleted,
 max(create_time) AS ctime 
FROM test_a 
GROUP BY user_id
HAVING deleted = 0;
函數說明:
◼ argMax(field1,field2):按照 field2 的最大值取 field1 的值。
當我們更新數據時,會寫入一行新的數據,例如上面語句中,通過查詢最大的create_time 得到修改后的 score 字段值。
(2)創建視圖,方便測試 
CREATE VIEW view_test_a AS
SELECT
 user_id ,
 argMax(score, create_time) AS score, 
 argMax(deleted, create_time) AS deleted,
 max(create_time) AS ctime 
FROM test_a 
GROUP BY user_id
HAVING deleted = 0;
(3)插入重復數據,再次查詢 
#再次插入一條數據
INSERT INTO TABLE test_a(user_id,score,create_time)
VALUES(0,'AAAA',now())


#再次查詢
SELECT *
FROM view_test_a
WHERE user_id = 0;
(4)刪除數據測試 
#再次插入一條標記為刪除的數據
INSERT INTO TABLE test_a(user_id,score,deleted,create_time) 
VALUES(0,'AAAA',1,now()); 

#再次查詢,剛才那條數據看不到了
SELECT *
FROM view_test_a
WHERE user_id = 0;
這行數據並沒有被真正的刪除,而是被過濾掉了。在一些合適的場景下,可以結合 表級別的 TTL 最終將物理數據刪除。

4 通過 FINAL 查詢

  在查詢語句后增加 FINAL 修飾符,這樣在查詢的過程中將會執行 Merge 的特殊邏輯(例如數據去重,預聚合等)。
  但是這種方法在早期版本基本沒有人使用,因為在增加 FINAL 之后,我們的查詢將會變成一個單線程的執行過程,查詢速度非常慢。
  在 v20.5.2.7-stable 版本中,FINAL 查詢支持多線程執行,並且可以通過 max_final_threads參數控制單個查詢的線程數。但是目前讀取 part 部分的動作依然是串行的。
  FINAL 查詢最終的性能和很多因素相關,列字段的大小、分區的數量等等都會影響到最終的查詢時間,所以還要結合實際場景取舍。
  參考鏈接:https://github.com/ClickHouse/ClickHouse/pull/10463
  使用 hits_v1 表進行測試:
  分別安裝了 20.4.5.36 和 21.7.3.14 兩個版本的 ClickHouse 進行對比。 
4.1 老版本測試
(1)普通查詢語句
select * from visits_v1 WHERE StartDate = '2014-03-17' limit 100;
(2)FINAL 查詢
select * from visits_v1 FINAL WHERE StartDate = '2014-03-17' limit 100;
先前的並行查詢變成了單線程。 
4.2 新版本測試
(1)普通語句查詢
select * from visits_v1 WHERE StartDate = '2014-03-17' limit 100 settings
max_threads = 2;
查看執行計划: 
explain pipeline select * from visits_v1 WHERE StartDate = '2014-03-17'
limit 100 settings max_threads = 2;

(Expression) 
ExpressionTransform × 2 
 (SettingQuotaAndLimits) 
 (Limit) 
 Limit 22 
 (ReadFromMergeTree)
 MergeTreeThread × 2 01
明顯將由 2 個線程並行讀取 part 查詢。
(2)FINAL 查詢
select * from visits_v1 final WHERE StartDate = '2014-03-17' limit 100  settings max_final_threads = 2
查詢速度沒有普通的查詢快,但是相比之前已經有了一些提升,查看 FINAL 查詢的執行計划: 
explain pipeline select * from visits_v1 final WHERE StartDate = '2014- 03-17' limit 100 settings max_final_threads = 2;
(Expression) 
ExpressionTransform × 2 
 (SettingQuotaAndLimits) 
 (Limit) 
 Limit 22 
 (ReadFromMergeTree) 
 ExpressionTransform × 2 
 CollapsingSortedTransform × 2
 Copy 12 
 AddingSelector 
 ExpressionTransform 
 MergeTree 01
從 CollapsingSortedTransform 這一步開始已經是多線程執行,但是讀取 part 部分的動作還是串行。 
 

 

 


 

 
 
 
 


免責聲明!

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



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