默认clickhouse-go用http协议(8123端口),但多数clickhouse实例仅开放tcp端口(9000),需在dsn中添加?protocol=tcp;tcp模式下不支持insert...values多行写法,须用stmt.exec()批量插入。

用 github.com/ClickHouse/clickhouse-go 连 ClickHouse 时连不上
默认配置下 clickhouse-go 使用的是 HTTP 协议,但很多 ClickHouse 实例(尤其是云服务或 Docker 镜像)默认只开 TCP 端口(9000),HTTP 端口(8123)可能被禁用或未暴露。
连不上最常见原因是协议不匹配,而不是账号密码错。
- 检查 ClickHouse 实例是否监听
8123:用curl -v http://host:8123/看能否返回Ping响应 - 如果只开放了
9000,必须改用 TCP 模式:在 DSN 中加?protocol=tcp,例如tcp://127.0.0.1:9000?database=default&protocol=tcp - 注意:TCP 模式下不支持
INSERT ... VALUES (...)的多行写法,必须用stmt.Exec()或批量stmt.Send(),否则报invalid packet
Query() 返回空 slice 却没报错
Rows.Scan() 不会自动分配切片容量,也不会校验列数是否匹配——这是 Go driver 最容易被忽略的“静默失败”点。
- 务必先调用
rows.Columns()检查字段名和类型,尤其当 SQL 里用了别名、聚合函数或嵌套结构时 - 扫描时用指针数组而非值数组:
var v1, v2 string; rows.Scan(&v1, &v2),否则所有字段都扫进第一个变量 - 如果查询含
Array(Tuple(...))或Map类型,原生clickhouse-go不支持直接 Scan,得用rows.ColumnTypes()+rows.Next()+rows.ScanValue()手动解析
大批量 INSERT 性能差,CPU 占用高
ClickHouse 是列式引擎,单条 INSERT 语句插入 1 行,等于触发一次小合并(minor merge),完全违背 OLAP 设计初衷。
- 必须用批量插入:每批 1000–10000 行,用
stmt.Exec()传入二维切片,如[][]interface{}{{1,"a"},{2,"b"}} - 避免用
db.Query("INSERT ...")拼 SQL,字符串拼接+参数逃逸会吃掉大量 GC 时间 - 如果数据来自 CSV/JSON 流,优先走
clickhouse-go的Writer接口(conn.Writer().Write()),它底层复用 TCP 连接并做缓冲,比 Stmt 快 3–5 倍
GROUP BY 后 COUNT() 结果不准,或者 ORDER BY 失效
ClickHouse 默认启用 optimize_sorting_by_input 和 distributed_group_by_no_merge 等优化开关,在分布式表或 JOIN 场景下,Go client 拿到的结果可能未经最终 merge。
立即学习“go语言免费学习笔记(深入)”;
- 在 SQL 开头显式加
SETTINGS distributed_group_by_no_merge = 0,强制服务端合并分片结果 - 对
COUNT(DISTINCT x),不要依赖近似函数(如uniq())除非业务允许误差;真要精确,得加SETTINGS max_bytes_before_external_group_by = 1000000000防止内存溢出 fallback 到磁盘 - ORDER BY 在子查询或 CTE 中可能被优化器忽略,外层必须再包一层
SELECT * FROM (...) ORDER BY ...
事情说清了就结束。ClickHouse 的“快”是建立在明确的数据模型和查询约束上的,Go client 只负责把请求发过去——它不会替你决定该不该建物化视图、要不要预聚合、字段类型是否匹配。这些决策点,都在 SQL 和表结构里。










