You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

103 lines
2.3 KiB

package ck
import (
"context"
"fmt"
"sig-pub/pkg/config"
"sig-pub/pkg/storage/persist"
"time"
"github.com/ClickHouse/clickhouse-go/v2/lib/driver"
clickhousev2 "github.com/ClickHouse/clickhouse-go/v2"
)
type ClickhouseBatchWriter struct {
cfg config.ClickhouseConfig
conn driver.Conn
}
func NewClickhouseBatchWriter(cfg config.ClickhouseConfig) *ClickhouseBatchWriter {
return &ClickhouseBatchWriter{
cfg: cfg,
}
}
func (c *ClickhouseBatchWriter) Init() (err error) {
options, err := c.cfg.Clickhousev2Options()
if err != nil {
return
}
// initial clickhouse conn
c.conn, err = clickhousev2.Open(options)
if err != nil {
return
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err = c.conn.Ping(ctx); err != nil {
if exception, ok := err.(*clickhousev2.Exception); ok {
err = fmt.Errorf("exception [%d] %s %s", exception.Code, exception.Message, exception.StackTrace)
}
return
}
return
}
// InsertBatch 批量插入gorm标签的结构体, 结构体用指针!
func InsertBatch[T any](c *ClickhouseBatchWriter, ctx context.Context, datas []T) (err error) {
if len(datas) == 0 {
return
}
var tColumns = make(map[string][]string, 3)
var tBatchs = make(map[string]driver.Batch, 3)
for _, data := range datas {
// 优化原生批量插入: https://clickhouse.com/docs/en/integrations/go#batch-insert
table, columns, values, e := persist.ReflectGormData(data)
if e != nil {
err = e
return
}
// 初始化该表 prepare
if _, ok := tColumns[table]; !ok {
tColumns[table] = columns
prepareSql := fmt.Sprintf("INSERT INTO %s(", table)
for i, column := range columns {
if i == 0 {
prepareSql += column
} else {
prepareSql += ("," + column)
}
}
prepareSql += ") SETTINGS async_insert=1, wait_for_async_insert=0"
batch, e := c.conn.PrepareBatch(ctx, prepareSql)
if e != nil {
err = e
return
}
tBatchs[table] = batch
}
columns = tColumns[table]
batch := tBatchs[table]
var args = make([]any, 0, len(columns))
for _, column := range columns {
args = append(args, values[column])
}
err = batch.Append(args...)
if err != nil {
return
}
}
// 批量插入
for _, batch := range tBatchs {
err = batch.Send()
if err != nil {
return
}
}
return
}