clickhouse连接需显式配协议、认证与时区,tcp用9000端口、http用8123端口且http下url密码无效;百万写入禁拼sql,应使用preparebatch或writer;查询必设context超时与服务端max_execution_time;扫描后须检查rows.err();nullable字段必须用sql.nullxxx而非*t。

连接必须显式配协议、认证与时区
连不上 ClickHouse,90% 不是密码错,而是协议和端口不匹配。TCP 模式(默认)走 9000 端口,HTTP 模式(云服务/某些托管平台常用)走 8123 端口,且 HTTP 下 DSN 中的 user:pass 会被忽略。
正确做法:
- TCP 连接:用
clickhouse.Options{Addr: []string{"host:9000"}, Auth: clickhouse.Auth{Username:"default", Password:"xxx"}} - HTTP 连接:必须显式设
Protocol: clickhouse.HTTP,并传Auth结构体,不能靠 URL 用户名密码 - 时区必须设:连接后立即执行
conn.Exec("SET timezone = 'Asia/Shanghai'"),或 DSN 加&timezone=Asia%2FShanghai,否则DateTime字段解析会偏移或报错
百万级写入别拼 SQL,用 PrepareBatch 或 Writer
单条 INSERT 或循环调 stmt.Exec() 在百万量级下极易 OOM —— 驱动会把每条语句当独立请求发,内存堆积 + GC 飙升。
可靠方案只有两个:
-
conn.PrepareBatch("INSERT INTO t"):每批控制在10000–100000行,调batch.Append(...)后batch.Send();复用batch.Reset()避免反复 new -
conn.Writer().Write():底层用 CSV 流,缓冲复用,吞吐比 batch 高 3–5 倍;适合数据来自bytes.Reader或io.Pipe的场景,不全量加载到内存
查询必带 context 超时与服务端限流
ClickHouse 查询不是越快越好,是越可控越好。没超时的查询可能卡死 goroutine,拖垮整个服务。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
两层防护缺一不可:
- 客户端侧:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second),所有Query/QueryRow都传这个 ctx - 服务端侧:SQL 里显式加
SETTINGS max_execution_time = 20,防慢查询占用资源 - 扫描后必须检查
rows.Err()—— ClickHouse 驱动不会在rows.Next()结束时自动暴露查询错误,漏判会导致静默失败
Nullable 字段必须用 sql.NullXxx,别用 *T
ClickHouse 的 Nullable(UInt64) 或 Nullable(String) 列,Go 里若用 *uint64 或 *string 扫描,遇到 NULL 会 panic:驱动无法把 NULL 映射到 nil 指针(底层解码逻辑不支持)。
唯一安全方式是用标准库的 sql.NullString、sql.NullInt64 等类型:
- 声明变量:
var name sql.NullString - 扫描:
rows.Scan(&name) - 取值前先判断:
if name.Valid { use(name.String) }
类型映射错位是线上最隐蔽的 panic 来源之一,尤其在字段后期改为 Nullable 时容易被忽略。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










