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.NullString
		var item2 sql.NullInt64
		err := 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:[email protected]: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 Error
	db.AddQueryHook(chdebug.NewQueryHook(chdebug.WithVerbose(true)))
	//联通测试
	if err = db.Ping(ctx); err != nil {
		return
	}

	// 测试打印Query
	klog.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.NullString
		var item2 sql.NullInt64
		err := 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.464
        select              7.588ms
        select id, age, name from userinfo u order by u.id

panic: reflect: call of reflect.Value.IsNil on struct Value

goroutine 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:[email protected]: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.NullString
		var item2 sql.NullInt64
		err := 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:[email protected]: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一致。后续可能向数据仓库,数据分析这方面研究,届时再看看。

猜你喜欢

转载自blog.csdn.net/subfate/article/details/129969742