gorm 官方 clickhouse 驱动已废弃(v1.25+ 返回 errnotimplemented,v2.x 彻底删除),因其语法、类型、分页等与传统数据库差异大,无法支持主键、事务、update/delete 等操作;必须改用 clickhouse-go/v2 原生驱动手写 sql,配合 block 批量插入和手动 scan 查询。

不能直接用 GORM 的标准 gorm.Open 方式连接 ClickHouse —— 它不兼容,会 panic 或静默失败。 因为 GORM 官方驱动 gorm.io/driver/clickhouse 实际上是空实现(v1.25+ 已明确标记为“experimental”,v2.x 彻底移除),且 ClickHouse 的 SQL 语法、类型系统、分页机制与传统关系型数据库差异极大,GORM 默认行为几乎全部失效。
为什么 gorm.io/driver/clickhouse 不能用
该包在 v1.25 后已停止维护,源码中 Open 函数直接返回 ErrNotImplemented;v2.x 版本中该驱动被完全删除。尝试调用会立即触发 panic:panic: unsupported driver: clickhouse。这不是配置问题,是设计层面的放弃支持。
- GORM 的 Model 映射依赖主键、自增、事务回滚等语义,而 ClickHouse 的
MergeTree引擎无主键概念,也无行级事务 -
Save()、Delete()、Update()等方法生成的 SQL 在 ClickHouse 上语法错误(如不支持UPDATE ... SET ... WHERE的标准形式) -
Offset()分页直接报错:Unsupported syntax: OFFSET,且性能灾难
正确做法:用原生 ClickHouse 驱动 + 手写 SQL
必须绕过 GORM,改用官方推荐的 github.com/ClickHouse/clickhouse-go/v2 驱动。它支持二进制协议、连接池、Block 批量写入,是当前生产环境唯一可靠选择。
- 安装:
go get github.com/ClickHouse/clickhouse-go/v2 - 连接示例(带基础健壮性):
import ( "context" "github.com/ClickHouse/clickhouse-go/v2" ) <p>conn := clickhouse.OpenDB(&clickhouse.Options{ Addr: []string{"127.0.0.1:9000"}, Auth: clickhouse.Auth{ Database: "default", Username: "default", Password: "", }, Settings: clickhouse.Settings{ "max_execution_time": 60, "insert_block_size": 10000, }, DialTimeout: 5 * time.Second, MaxOpenConns: 10, MaxIdleConns: 5, })</p><p>if err := conn.Ping(context.Background()); err != nil { log.Fatal(err) } </p> - 不要用
database/sql封装层(如sql.Open("clickhouse", ...)),它屏蔽了 v2 驱动的关键特性(如 Block 插入、压缩、低延迟设置)
如果非要保留 GORM 表结构定义,只能做「伪 ORM」
你可以复用 GORM 的 struct tag(如 gorm:"column:xxx")来声明字段映射,但所有数据库操作必须手写 SQL 并用原生驱动执行。GORM 的 db.Create() 等方法一概禁用。
- struct 示例:
type EventLog struct { ID uint64 `gorm:"column:id"` Timestamp int64 `gorm:"column:timestamp"` UserID string `gorm:"column:user_id"` Action string `gorm:"column:action"` } - 插入必须用 Block 模式(否则性能极差):
block := clickhouse.NewBlock() block.AddColumn("id", []uint64{log.ID}) block.AddColumn("timestamp", []int64{log.Timestamp}) block.AddColumn("user_id", []string{log.UserID}) block.AddColumn("action", []string{log.Action}) <p>if err := conn.BatchInsert(context.Background(), "event_log", block); err != nil { log.Fatal(err) } </p> - 查询结果需手动 Scan 到 struct 字段,GORM 的
Find(&slice)不可用
真正麻烦的不是连接本身,而是后续所有数据操作都得按 ClickHouse 的规则重写:建表要指定 ENGINE 和 ORDER BY,分页必须用游标,聚合要用 GROUP BY + 跳数索引字段,连字符串比较都要注意大小写敏感策略。把 MySQL 思维带进来,十有八九查不到数据或查得极慢。











