ClickHouse连接与操作问题多源于clickhouse-go/v2配置不当:端口错用(8123 HTTP vs 9000 TCP)、TLS未显式关闭、压缩不匹配;INSERT应批量用PrepareBatch+Send;ScanStruct依赖精确ch标签;空结果需检查rows.Err()。
连不上不是网络问题,八成是协议或参数错位;单条 INSERT 写百万行,性能差十倍不止;ScanStruct 字段不赋值却不报错——这些都不是 ClickHouse 本身的问题,而是 clickhouse-go/v2 的行为惯性在坑人。
clickhouse.Open 连接失败的三个高频原因
驱动默认走 TCP 协议 + TLS + LZ4 压缩,但本地开发环境往往只开了裸 TCP(9000 端口)且没配证书。你看到的
或静默卡住,基本都出在这儿。
写成
:这是 HTTP 端口,v2 默认走 TCP,得改成
没关 TLS:
必须显式加在 DSN 或 Options 里,否则握手失败,日志里不提示 TLS 相关错误,只超时
压缩不匹配:服务端没开 LZ4(查
),但客户端用了
,会报
INSERT 性能差?别用 stmt.Exec 循环插
ClickHouse 不是关系型数据库,单行 INSERT 触发的是小块写入+ minor merge,完全违背列式存储的设计前提。10 万行用循环
可能要几十秒;换成真批量,通常压到 1 秒内。
必须用
获取
对象,不是
只是攒数据,不发包;必须调
才真正提交
每批控制在 1w–10w 行之间:太小吞吐上不去,太大易触发服务端
限制或 OOM
别传 struct 实例:
会 panic,必须按列拆成
、
等切片分别 append
rows.ScanStruct 字段不赋值却没报错
v2 的
完全依赖结构体字段上的
标签,且大小写、拼写必须和 ClickHouse 列名严格一致。漏标、标错、大小写不匹配,它就跳过该字段——不 panic,不 warn,只给零值。
立即学习
“
go语言免费学习笔记(深入)
”;
结构体字段必须带
,例如
ClickHouse 列是
,结构体里写成
却没标
,那
就永远是 0
不认
标签,也完全忽略
或
如果表字段含
,字段类型不能是
,得用
或
(后者更贴合语义)
Query 返回空结果但 rows.Err() 是 nil
这是最隐蔽的“假成功”:SQL 执行了,没报错,rows.Next() 返回 false,你以为没数据,其实是扫描中途出错被吞了。
必须在
循环结束后,立刻检查
,很多“空结果”其实是这里出的错
别用
:字段顺序、别名、聚合函数会让
地址传参错位,优先显式写出字段名,并严格按顺序传
时间类型注意时区:
默认是 UTC,而
是本地时区,WHERE 条件比较前先统一用
或
字符串字段含 NULL?用
会 panic,得用
或
真正的难点不在语法,而在协议细节与类型对齐:TCP 端口和 HTTP 端口不能混,TLS 和压缩开关必须和服务端配置咬合,字段标签一个字母都不能错,NULL 和非 NULL 类型不能靠猜——这些地方一松懈,程序就静默失效。
context deadline exceededAddr"localhost:8123""localhost:9000"secure=falseSELECT * FROM system.settings WHERE name LIKE '%compression%'clickhouse.Compression(clickhouse.CompressionLZ4)Code: 287. DB::Exception: Unknown compression methodstmt.Exec()conn.PrepareBatch()Batchconn.Prepare()batch.Append()batch.Send()max_insert_block_sizebatch.Append(row)[]int64[]stringScanStructch:ch:"column_name"Ts time.Time `ch:"event_time"`user_idUserIDch:"user_id"UserIDScanStructjson:db:sql:Nullable(String)*stringsql.NullStringch.Stringfor rows.Next()if err := rows.Err(); err != nilSELECT *Scan()&id, &name, &tsDateTimetime.Now().UTC().In(loc)*stringsql.NullStringch.String