您可以通过开源的 ClickHouse Go 驱动程序连接到 ByteHouse 云数仓版,连接后进行数据写入查询等操作。本文为您介绍 ClickHouse Go 驱动连接 ByteHouse 云数仓版的主要操作流程和操作要点。
由于 ByteHouse 的 Go 驱动当前在维护升级中,您可以使用开源 ClickHouse 的 Go 驱动连接 ByteHouse,开源 ClickHouse 支持的 API 接口和协议如下。
细分项 | 能力说明 |
|---|---|
API 接口 | 支持:
|
协议 | 支持:
|
推荐使用以下版本:
驱动 | 已验证版本 |
|---|---|
ClickHouse Go 基础驱动 | 2.30.0 |
Go | Golang 1.21 |
单击该链接下载 ClickHouse Go 基础驱动。
您可以通过 go get 安装。
go get github.com/ClickHouse/clickhouse-go/v2@v2.30.0
ByteHouse 支持通过 IAM 用户或数据库用户连接 ClickHouse Go Driver。IAM 用户与数据库用户二者差异说明如下,您可按需选择。
更多 IAM 用户和数据库用户的介绍请参见以下文档:
请参考步骤三:获取 ByteHouse 连接串信息,了解如何通过 IAM 用户方式连接到 ByteHouse。
通用参数说明如下:
参数 | 配置要点 |
|---|---|
Host | Host 在不同协议中的字段不同,但格式相同,为 |
Port |
|
Database | 配置为连接 ByteHouse 的数据库名称。 |
username & password |
|
virtual_warehouse | 配置为计算组名。您可登录 ByteHouse 控制台,单击顶部计算组,查看并复制计算组 ID。示例: |
请参考步骤三:获取 ByteHouse 连接串信息,了解如何通过数据库用户的方式连接到 ByteHouse。
通用参数说明如下:
参数 | 配置要点 |
|---|---|
Host | Host 在不同协议中的字段不同,但格式相同,为 |
Port |
|
Database | 配置为连接 ByteHouse 的数据库名称。 |
username & password |
|
virtual_warehouse | 配置为计算组名。您可登录 ByteHouse 控制台,单击顶部计算组,查看并复制计算组 ID。示例: |
可参考下面代码连接至 ByteHouse,使用时注意替换连接语句中的 {Host}、{Password}、{User}、{Database}、{VIRTUAL_WAREHOUSE_ID} 等连接信息字段,获取方式请参见获取 ByteHouse 连接信息。
keepAlive,可以复用连接和避免短链接。使用 ClickHouse Driver 的 OpenDB 创建连接
import ( "context" //"crypto/tls" "database/sql" "fmt" "github.com/ClickHouse/clickhouse-go/v2" "github.com/google/uuid" "time" ) func main() { host := "{Host}" port := 19000 password := "{Password}" user := "{User}" database := "{Database}" virtual_warehouse_id := "{VIRTUAL_WAREHOUSE_ID}" db := clickhouse.OpenDB(&clickhouse.Options{ Addr: []string{fmt.Sprintf("%s:%d", host, port)}, Auth: clickhouse.Auth{ Database: database, Username: user, Password: password, }, Protocol: clickhouse.Native, TLS: &tls.Config{ InsecureSkipVerify: true, }, Settings: clickhouse.Settings{ "virtual_warehouse": virtual_warehouse_id, }, })
通过 Go Database 的 DSN(Data Source Name,数据源名称)创建连接
import ( "context" //"crypto/tls" "database/sql" "fmt" "github.com/ClickHouse/clickhouse-go/v2" "github.com/google/uuid" "time" ) func main() { host := "{Host}" port := 19000 password := "{Password}" user := "{User}" database := "{Database}" virtual_warehouse_id := "{VIRTUAL_WAREHOUSE_ID}" db, err := sql.Open( "clickhouse", fmt.Sprintf("clickhouse://%v:%v@%v:%v/%v?secure=true&virtual_warehouse=%v", user, password, host, port, database, virtual_warehouse_id), ) if err != nil { log.Fatal(err) }
使用 HTTP 协议时,全局连接时,必须添加 describe_query_with_data_type_flags=0 参数。
使用 ClickHouse Driver 的 OpenDB 创建连接
import ( "context" //"crypto/tls" "database/sql" "fmt" "github.com/ClickHouse/clickhouse-go/v2" "github.com/google/uuid" "time" ) func main() { host := "{Host}" port := 8123 password := "{Password}" user := "{User}" database := "{Database}" virtual_warehouse_id := "{VIRTUAL_WAREHOUSE_ID}" db := clickhouse.OpenDB(&clickhouse.Options{ Addr: []string{fmt.Sprintf("%s:%d", host, port)}, Auth: clickhouse.Auth{ Database: database, Username: user, Password: password, }, Protocol: clickhouse.HTTP, TLS: &tls.Config{ InsecureSkipVerify: true, }, Settings: clickhouse.Settings{ "virtual_warehouse": virtual_warehouse_id, "describe_query_with_data_type_flags": "0", }, })
通过 Go Database 的 DSN(Data Source Name,数据源名称)创建连接
import ( "context" //"crypto/tls" "database/sql" "fmt" "github.com/ClickHouse/clickhouse-go/v2" "github.com/google/uuid" "time" ) func main() { host := "{Host}" port := 8123 password := "{Password}" user := "{User}" database := "{Database}" virtual_warehouse_id := "{VIRTUAL_WAREHOUSE_ID}" db, err := sql.Open( "clickhouse", fmt.Sprintf("https://%v:%v@%v:%v/%v?secure=true&describe_query_with_data_type_flags=0&virtual_warehouse=%v", user, password, host, port, database, virtual_warehouse_id), ) if err != nil { log.Fatal(err) }
您可使用 Context 设置 query ID。
func UseContextSendQueryId(db *sql.DB) { queryId, _ := uuid.NewUUID() ctx := clickhouse.Context(context.Background(), clickhouse.WithQueryID(fmt.Sprintf("customer_%v", queryId.String()))) _, err := db.ExecContext(ctx, "DROP DATABASE IF EXISTS bhgotest") if err != nil { log.Fatal(err) } }
func UseContextSendQuerySetting(db *sql.DB) { // we can use context to pass settings to a specific API call ctx := clickhouse.Context(context.Background(), clickhouse.WithSettings(clickhouse.Settings{ "max_execution_time": 450, })) var settingValue uint16 if err := db.QueryRowContext(ctx, "SELECT getSetting('max_execution_time')").Scan(&settingValue); err != nil { log.Fatal(err) } fmt.Printf("settingValue: %v\n", settingValue) if settingValue != 450 { panic(fmt.Sprintf("expected setting value to be 450, got %d", settingValue)) } }
您可以使用以下代码连接 ByteHouse,并管理数据。
import ( "context" //"crypto/tls" "database/sql" "fmt" "github.com/ClickHouse/clickhouse-go/v2" "github.com/google/uuid" "time" ) func main() { host := "{Host}" port := 8123 // 根据协议选择8123(HTTP)还是19000(TCP) password := "{Password}" user := "{User}" database := "{Database}" virtual_warehouse_id := "{VIRTUAL_WAREHOUSE_ID}" //db := clickhouse.OpenDB(&clickhouse.Options{ // Addr: []string{fmt.Sprintf("%s:%d", host, port)}, // Auth: clickhouse.Auth{ // Database: database, // Username: user, // Password: password, // }, // Protocol: clickhouse.Native, // TLS: &tls.Config{ // InsecureSkipVerify: true, // }, // Settings: clickhouse.Settings{ // "virtual_warehouse": virtual_warehouse_id, // }, //}) db, err := sql.Open( "clickhouse", fmt.Sprintf("clickhouse://%v:%v@%v:%v/%v?secure=true&virtual_warehouse=%v", user, password, host, port, database, virtual_warehouse_id), ) if err != nil { log.Fatal(err) } defer db.Close() if err := db.Ping(); err != nil { log.Fatal(err) } UseContextSendQueryId(db) UseContextSendQuerySetting(db) _, err = db.Exec("DROP DATABASE IF EXISTS bhgotest") if err != nil { log.Fatal(err) } _, err = db.Exec("CREATE DATABASE IF NOT EXISTS bhgotest") if err != nil { log.Fatal(err) } _, err = db.Exec(` CREATE TABLE IF NOT EXISTS bhgotest.example ( Col1 UInt8 , Col2 String , Col3 FixedString(3) , Col4 UUID , Col5 Map(String, UInt8) , Col6 Array(String) , Col7 Tuple(String, UInt8, Array(Map(String, String))) KV , Col8 DateTime ) Engine = CnchMergeTree() ORDER BY tuple() `) if err != nil { log.Fatal(err) } batchInsert, err := db.Begin() if err != nil { log.Fatal(err) } batchInsertPrepare, err := batchInsert.Prepare("INSERT INTO bhgotest.example") if err != nil { log.Fatal(err) } for i := 0; i < 1000; i++ { _, err := batchInsertPrepare.Exec( uint8(42), "ClickHouse", "Inc", uuid.New(), map[string]uint8{"key": 1}, // Map(String, UInt8) []string{"Q", "W", "E", "R", "T", "Y"}, // Array(String) []any{ // Tuple(String, UInt8, Array(Map(String, String))) "String Value", uint8(5), []map[string]string{ {"key": "value"}, {"key": "value"}, {"key": "value"}, }, }, time.Now(), ) if err != nil { log.Fatal(err) } } batchInsert.Commit() row := db.QueryRow("SELECT * FROM bhgotest.example limit 1") var ( col1 uint8 col2, col3, col4 string col5 map[string]uint8 col6 []string col7 interface{} col8 time.Time ) if err := row.Scan(&col1, &col2, &col3, &col4, &col5, &col6, &col7, &col8); err != nil { log.Fatal(err) } print(col1, col2, col3, col4, col5, col6, col7) db.Exec("DROP TABLE IF EXISTS bhgotest.example") } func UseContextSendQueryId(db *sql.DB) { queryId, _ := uuid.NewUUID() ctx := clickhouse.Context(context.Background(), clickhouse.WithQueryID(fmt.Sprintf("customer_%v", queryId.String()))) _, err := db.ExecContext(ctx, "DROP DATABASE IF EXISTS bhgotest") if err != nil { log.Fatal(err) } } func UseContextSendQuerySetting(db *sql.DB) { // we can use context to pass settings to a specific API call ctx := clickhouse.Context(context.Background(), clickhouse.WithSettings(clickhouse.Settings{ "max_execution_time": 450, })) var settingValue uint16 if err := db.QueryRowContext(ctx, "SELECT getSetting('max_execution_time')").Scan(&settingValue); err != nil { panic(err) } fmt.Printf("settingValue: %v\n", settingValue) if settingValue != 450 { panic(fmt.Sprintf("expected setting value to be 450, got %d", settingValue)) } }