> 文章列表 > Golang实践录:go-clickhouse的使用

Golang实践录:go-clickhouse的使用

Golang实践录:go-clickhouse的使用

某项目需要查询clickhouse数据库,本文是使用过程的一些记录、笔记,不具权威性。

概述

笔者一直不熟悉数据库,只知道几个select语句。正如不熟悉Android开发、Java开发一样。但最近的项目切实使用到的了,而且项目被上峰拔到很高的层次,据说主任级别领导亲自过问了。该项目需要查询数据库,并做一些必要的统计和分析,但oracle数据库量实在太多,查询很耗时,经询问得到部署了一套clickhouse的数据库,可能是集群可能是分布式。但对我而言只是一个数据库,测试发现,速度快很多很多很多,除了最近1、2小时外,历史数据基本一致,于是,决定在项目中使用这个库,go有很多相关的客户端,有的无法使用,但最终找到一个合适的客户端。

  • 个别客户端支持的clickhouse版本较新,但生产数据库的版本比较旧,所以无法使用。
  • 生产数据库只支持http连接方式。
  • 为了方便测试,用容器方式重新部署了数据库。

使用github.com/ClickHouse/clickhouse-go/v2

github仓库在此,下载:

go get github.com/ClickHouse/clickhouse-go/v2

测试代码:

import ("database/sql"_ "github.com/ClickHouse/clickhouse-go/v2"
)
func CreateClickHouse_bad(dbstr string) (sqldb *sql.DB, err error) {rdbstr = "http://latelee.cn:8082/default?username=default&password=123456"klog.Println("connn  ", rdbstr)sqldb, err = sql.Open("clickhouse", rdbstr) // 去掉前缀if err != nil {return nil, errors.New("open database failed: " + err.Error())}err = sqldb.Ping()if err != nil {return nil, errors.New("connect database failed: " + err.Error())}klog.Println("connect to clickhouse ok")//log.Println("connect to ", dbParam.server, dbParam.database, "ok")// test...results, err := sqldb.Query(`select id, age, name from userinfo u order by u.id`)if err != nil {klog.Println("Query error: ", err)return}for results.Next() {var item1, item3 sql.NullStringvar item2 sql.NullInt64err := results.Scan(&item1, &item2, &item3)if err != nil {klog.Println("scan error: ", err)break}if !item1.Valid {continue}klog.Println("dddddddddd ", item1.String, item2.Int64, item3.String)// break}os.Exit(0)return
}

结果:

2023-03-22 00:19:05.031  INFO   -  connecting db...
2023-03-22 00:19:05.031  INFO   -  connn   http://latelee.cn:8082/default?username=default&password=123456
WARNING: version 21.9.6 of ClickHouse is not supported by this client
2023-03-22 00:19:05.131  INFO   -  connect to clickhouse ok
2023-03-22 00:19:05.154  INFO   -  scan error:  sql: Scan error on column index 0, name "id": unsupported Scan, storing driver.Value type *string into type *string

尝试

根据of ClickHouse is not supported by this client搜索源码,发现其支持特定版本的数据库。

找到github.com\\ClickHouse\\clickhouse-go\\v2\\resources\\meta.yml文件,内容如下:

clickhouse_versions:- 22.3- 22.8- 22.9- 22.10- 22.11
go_versions:- 1.18- 1.19

手动将版本号添加到该文件,错误依旧。

网上较多使用该版本,但无法用于项目,舍弃。

使用github.com/uptrace/go-clickhouse/ch

github仓库在此,下载:

go get github.com/uptrace/go-clickhouse/ch
go get github.com/uptrace/go-clickhouse/chdebug

测试代码:

import ("database/sql""github.com/uptrace/go-clickhouse/ch""github.com/uptrace/go-clickhouse/chdebug"
)func CreateClickHouse_bad1(dbstr string) (sqldb *sql.DB, err error) {ctx := context.Background()constr := "clickhouse://default:123456@latelee.cn:9000/default?sslmode=disable"aaa := fmt.Sprintf("clickhouse://%s:%s@%s:%d/%s?sslmode=disable","default","","localhost",9000,"testUSER",)klog.Println("connn  ", constr)klog.Println("aaa  ", aaa)db := ch.Connect(ch.WithDSN(constr),ch.WithTimeout(5*time.Second),ch.WithDialTimeout(5*time.Second),ch.WithReadTimeout(5*time.Second),ch.WithWriteTimeout(5*time.Second),ch.WithPoolSize(100),)//打印Query Errordb.AddQueryHook(chdebug.NewQueryHook(chdebug.WithVerbose(true)))//联通测试if err = db.Ping(ctx); err != nil {return}// 测试打印Queryklog.Println("db ", db)// results, err := sqldb.QueryContext(ctx, `// select id, age, name from userinfo u order by u.id// `)results, err := db.Query(`select id, age, name from userinfo u order by u.id`)if err != nil {klog.Println("Query error: ", err)return}for results.Next() {var item1, item3 sql.NullStringvar item2 sql.NullInt64err := results.Scan(&item1, &item2, &item3)if err != nil {klog.Println("scan error: ", err)break}if !item1.Valid {continue}klog.Println("dddddddddd ", item1.String, item2.Int64, item3.String)}os.Exit(0)return
}

结果:

2023-03-22 00:28:51.456  INFO   -  db  DB<addr: latelee.cn:9000>
[ch]  00:28:51.464select              7.588msselect id, age, name from userinfo u order by u.idpanic: reflect: call of reflect.Value.IsNil on struct Valuegoroutine 1 [running]:
reflect.Value.IsNil(...)D:/go/src/reflect/value.go:1506
github.com/uptrace/go-clickhouse/ch/chschema.(*NullableColumn).ConvertAssign(0xc0004a4080, 0x0, {0x15d9600?, 0xc0000965b8?, 0x23195500598?})E:/project/golang_test/dbtool/vendor/github.com/uptrace/go-clickhouse/ch/chschema/column_nullable.go:85 +0x19d
github.com/uptrace/go-clickhouse/ch.(*Rows).Scan(0xc00052e210, {0xc0007a3b50, 0x3, 0x1692676?})

使用心得:

按项目主页,其性能比ClickHouse/clickhouse-go好。

根据官方手册,其支持model,但笔者所涉及库字段超百,对该模式的访问未研究,舍弃。

可能不支持http。示例代码均使用9000端口。在示例代码中未找到。

使用github.com/mailru/go-clickhouse/v2

github仓库在此,下载:

go get github.com/mailru/go-clickhouse/v2

测试代码:

import ("database/sql"_ "github.com/mailru/go-clickhouse/v2"
)func CreateClickHouse(dbstr string) (sqldb *sql.DB, err error) {rdbstr := dbstr[len("clickhouse:"):]rdbstr = "http://default:123456@latelee.cn:8082/default"klog.Println("connn  ", rdbstr)sqldb, err = sql.Open("chhttp", rdbstr) // 去掉前缀if err != nil {return nil, errors.New("open database failed: " + err.Error())}err = sqldb.Ping()if err != nil {return nil, errors.New("connect database failed: " + err.Error())}klog.Println("connect to clickhouse ok")//log.Println("connect to ", dbParam.server, dbParam.database, "ok")results, err := sqldb.Query(`select id, age, name from userinfo u order by u.id`)if err != nil {klog.Println("Query error: ", err)return}for results.Next() {var item1, item3 sql.NullStringvar item2 sql.NullInt64err := results.Scan(&item1, &item2, &item3)if err != nil {klog.Println("scan error: ", err)break}if !item1.Valid {continue}klog.Println("dddddddddd ", item1.String, item2.Int64, item3.String)// break}os.Exit(0)return
}

结果:

2023-03-22 00:34:35.435  INFO   -  connecting db...
2023-03-22 00:34:35.435  INFO   -  connn   http://default:123456@latelee.cn:8082/default
2023-03-22 00:34:35.495  INFO   -  connect to clickhouse ok
2023-03-22 00:34:35.520  INFO   -  dddddddddd  001 250 latelee
2023-03-22 00:34:35.520  INFO   -  dddddddddd  002 252 latelee2
2023-03-22 00:34:35.520  INFO   -  dddddddddd  003 253 latelee3
2023-03-22 00:34:35.520  INFO   -  dddddddddd  004 254 latelee4
2023-03-22 00:34:35.520  INFO   -  dddddddddd  005 255 latelee5

最终使用该客户端

小结

目前没有对clickhouse有太深度的研究,在go的查询,也保持和oracle一致。后续可能向数据仓库,数据分析这方面研究,届时再看看。