更新、刪除語法
Clickhouse通過alter方式實現更新、刪除,它把update、delete操作叫做mutation(突變)。語法為:
ALTER TABLE [db.]table DELETE WHERE filter_expr
ALTER TABLE [db.]table UPDATE column1 = expr1 [, ...] WHERE filter_expr
那么,mutation與標准的update、delete有什么區別呢?
標准SQL的更新、刪除操作是同步的,即客戶端要等服務端反回執行結果(通常是int值);而Clickhouse的update、delete是通過異步方式實現的,當執行update語句時,服務端立即反回,但是實際上此時數據還沒變,而是排隊等着。
查看mutation隊列
那么,怎么查看數據是否更新完成了呢?
可以通過system.mutations表查看相關信息:
SELECT
database,
table,
command,
create_time,
is_done
FROM system.mutations
LIMIT 10
┌─database─┬─table─────────────────┬─command─────────────────────────────────────────────────────────────────────────────┬─────────create_time─┬─is_done─┐
│ app │ scene_model │ UPDATE status = '2' WHERE id = '208209306' │ 2020-03-30 15:38:58 │ 1 │
│ app │ scene_model │ UPDATE status = '2' WHERE id = '100000004' │ 2020-03-30 15:40:00 │ 1 │
│ app │ scene_model │ UPDATE status = '2' WHERE id = '100000004' │ 2020-03-30 15:41:09 │ 1 │
│ app │ user_model │ UPDATE name = 'zhuweiming' WHERE id = '0000000047fd31e40147fd3477cc0000' │ 2020-03-19 18:34:59 │ 1 │
│ app │ work_statistics_total │ UPDATE pv = 10000, uv = 10000 WHERE (id = '1000900') AND (product = 'tracker_view') │ 2020-03-31 14:45:59 │ 1 │
│ app │ work_statistics_total │ UPDATE pv = 10000, uv = 10000 WHERE (id = '1000901') AND (product = 'tracker_view') │ 2020-03-31 14:45:59 │ 1 │
│ app │ work_statistics_total │ UPDATE pv = 10000, uv = 10000 WHERE (id = '1000902') AND (product = 'tracker_view') │ 2020-03-31 14:45:59 │ 1 │
│ app │ work_statistics_total │ UPDATE pv = 10000, uv = 10000 WHERE (id = '1000903') AND (product = 'tracker_view') │ 2020-03-31 14:45:59 │ 1 │
│ app │ work_statistics_total │ UPDATE pv = 10000, uv = 10000 WHERE (id = '1000904') AND (product = 'tracker_view') │ 2020-03-31 14:45:59 │ 1 │
│ app │ work_statistics_total │ UPDATE pv = 10000, uv = 10000 WHERE (id = '1000905') AND (product = 'tracker_view') │ 2020-03-31 14:45:59 │ 1 │
└──────────┴───────────────────────┴─────────────────────────────────────────────────────────────────────────────────────┴─────────────────────┴─────────┘
- database: 庫名
- table: 表名
- command: 更新/刪除語句
- create_time: mutation任務創建時間,系統按這個時間順序處理數據變更
- is_done: 是否完成,1為完成,0為未完成
除了上述的,還有一些其他的字段,詳見:官方文檔。
通過以上信息,可以查看當前有哪些mutation已經完成,is_done為1即表示已經完成。
Mutation具體過程
首先,使用where條件找到需要修改的分區;
然后,重建每個分區,用新的分區替換舊的,分區一旦被替換,就不可回退;
對於每個分區,可以認為是原子性的;但對於整個mutation,如果涉及多個分區,則不是原子性的。
注意事項
- 更新功能不支持更新有關主鍵或分區鍵的列
- 更新操作沒有原子性,即在更新過程中select結果很可能是一部分變了,一部分沒變,從上邊的具體過程就可以知道
- 更新是按提交的順序執行的
- 更新一旦提交,不能撤銷,即使重啟clickhouse服務,也會繼續按照system.mutations的順序繼續執行
- 已完成更新的條目不會立即刪除,保留條目的數量由finished_mutations_to_keep存儲引擎參數確定。 超過數據量時舊的條目會被刪除
- 更新可能會卡住,比如
update intvalue='abc'
這種類型錯誤的更新語句執行不過去,那么會一直卡在這里,此時,可以使用KILL MUTATION
來取消,語法:
kill kutation where database='app' and table='test' // database、table是system.mutations表中的字段
使用建議
按照官方的說明,update/delete 的使用場景是一次更新大量數據,也就是where條件篩選的結果應該是一大片數據。
舉例:alter table test update status=1 where status=0 and day='2020-04-01'
,一次更新一天的數據。
那么,能否一次只更新一條數據呢?例如:alter table test update pv=110 where id=100
當然也可以,但頻繁的這種操作,可能會對服務造成壓力。這很容易理解,如上文提到,更新的單位是分區,如果只更新一條數據,那么需要重建一個分區;如果更新100條數據,而這100條可能落在3個分區上,則需重建3個分區;相對來說一次更新一批數據的整體效率遠高於一次更新一行。
對於頻繁單條更新的這種場景,建議使用ReplacingMergeTree
引擎來變相解決。
鏈接:https://www.jianshu.com/p/521f2d1611f8