久久精品人人爽,华人av在线,亚洲性视频网站,欧美专区一二三

ClickHouse是如何批量寫入的

186次閱讀
沒有評論

共計 2333 個字符,預計需要花費 6 分鐘才能閱讀完成。

這篇文章將為大家詳細講解有關 ClickHouse 是如何批量寫入的,文章內容質量較高,因此丸趣 TV 小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

簡介

批量寫入又稱為 bulk write,對于單表插入多條數據的場景,可以減少插入請求數量,提高吞吐量和效率。clickhouse 官方 Golang 驅動 clickhouse-go[1]支持該關鍵特性,但是文檔的介紹不是很詳細,只有一句:

Bulk write support : begin- prepare- (in loop exec)- commit

 

并沒有詳細介紹用法和原理,筆者在開發業務時使用的庫是 sqlx[2],sql 也支持 clickhouse-go 驅動。參考了官方樣例代碼[3]:

...
tx, err := connect.Begin()
checkErr(err)
stmt, err := tx.Prepare(INSERT INTO example (country_code, os_id, browser_id, categories, action_day, action_time) VALUES (?, ?, ?, ?, ?, ?) )
checkErr(err)

for i := 0; i   100; i++ {
 if _, err := stmt.Exec(
  RU ,
 10+i,
 100+i,
 []int16{1, 2, 3},
 time.Now(),
 time.Now(),
 ); err != nil {
 log.Fatal(err)
 }
}
...

 

我寫的 bulk write 類似上面的代碼,但是提交給同事 review 時,他提出了疑問:stmt.Exec 是每次執行都發送寫請求到數據庫嗎?這個問題其實我不敢肯定,官方文檔也說得不明確。考慮到嚴謹性,讓自己的 PR 更有說服力,自己去翻看了相關源代碼。

這里需要指出,如果利用編輯器里的代碼跳轉功能會跳到 database/sql 庫中的 Exec 函數實現,實際上我們要看的代碼是 clickhouse-go 中的實現,至于編輯器跳轉到 database/sql 中的原因,書寫此文時筆者也沒弄清楚,先挖個坑吧。

  核心實現

stmt.Exec 的核心代碼如下[4]:

func (stmt *stmt) execContext(ctx context.Context, args []driver.Value) (driver.Result, error) {
 if stmt.isInsert {
 stmt.counter++
 if err := stmt.ch.block.AppendRow(args); err != nil {
 return nil, err
 }
 if (stmt.counter % stmt.ch.blockSize) == 0 {
 stmt.ch.logf([exec] flush block )
 if err := stmt.ch.writeBlock(stmt.ch.block); err != nil {
 return nil, err
 }
 if err := stmt.ch.encoder.Flush(); err != nil {
 return nil, err
 }
 }
 return emptyResult, nil
 }
 if err := stmt.ch.sendQuery(stmt.bind(convertOldArgs(args))); err != nil {
 return nil, err
 }
 if err := stmt.ch.process(); err != nil {
 return nil, err
 }
 return emptyResult, nil
}

 

上面的代碼不多,非常清晰,當執行 Exec 時,stmt.ch.block.AppendRow(args)會先把 sql 參數附加到本地緩存 block 中,然后 (stmt.counter % stmt.ch.blockSize) 判斷本地緩存大小是否到達閾值,到達則執行 Flush(),將數據寫入遠端。綜上,clickhouse-go 中的核心實現邏輯是:

底層維護一個緩存 block,同時設置 block_size 控制緩存大小執行 stmt.Exec 時,不會直接寫入遠程 ClickHouse 中,而是將插入參數 Append 到 block 中每次 Append 后,判斷 block 的 size 和 block_size 的關系,如果正好整除,則刷新 block(即寫入 clickhouse)

因此 block_size 這個參數很重要,它表示本地緩存的上限,如果很大的話,程序會占用一些內存。筆者起初設置為 100000,在調試日志中看不到 stmt.ch.logf([exec] flush block )打印的 log,設置小后就看到下面的輸出:

...
[clickhouse][connect=1][begin] tx=false, data=false
[clickhouse][connect=1][prepare]
[clickhouse][connect=1][read meta]  - data: packet=1, columns=6, rows=0
[clickhouse][connect=1][exec] flush block
[clickhouse][connect=1][exec] flush block
....

 
 

關于 ClickHouse 是如何批量寫入的就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

正文完
 
丸趣
版權聲明:本站原創文章,由 丸趣 2023-08-16發表,共計2333字。
轉載說明:除特殊說明外本站除技術相關以外文章皆由網絡搜集發布,轉載請注明出處。
評論(沒有評論)
主站蜘蛛池模板: 海晏县| 舞钢市| 黎平县| 冕宁县| 公安县| 武义县| 泽州县| 和林格尔县| 大冶市| 留坝县| 安顺市| 聂荣县| 左贡县| 陕西省| 水城县| 云林县| 弥勒县| 镇江市| 育儿| 云阳县| 西宁市| 日喀则市| 海阳市| 凤冈县| 老河口市| 噶尔县| 余江县| 柳州市| 老河口市| 金寨县| 新泰市| 广宁县| 绥中县| 虞城县| 崇义县| 伊宁县| 牡丹江市| 麻江县| 庄浪县| 南木林县| 沙田区|