Connecting
The following example, which returns the server version, demonstrates connecting to ClickHouse - assuming ClickHouse isn’t secured and accessible with the default user. Note we use the default native port to connect.conn variable has been created and is available.
Execution
Arbitrary statements can be executed via theExec method. This is useful for DDL and simple statements. It shouldn’t be used for larger inserts or query iterations.
Batch insert
To insert a large number of rows, the client provides batch semantics. This requires the preparation of a batch to which rows can be appended. This is finally sent via theSend() method. Batches are held in memory until Send is executed.
It is recommended to call Close on the batch to prevent leaking connections. This can be done via the defer keyword after preparing the batch. This will clean up the connection if Send never gets called. Note that this will result in 0 row inserts showing up in the query log if no rows were appended.
Ephemeral columns
Ephemeral columns are write-only columns that exist only during insertion — they are not stored and cannot be selected. They are useful for computing derived column values at insert time.Querying rows
You can either query for a single row using theQueryRow method or obtain a cursor for iteration over a result set via Query. While the former accepts a destination for the data to be serialized into, the latter requires the call to Scan on each row.
SELECT statement - by default, the order of column declaration will be used in the event of a SELECT * as shown above.
Similar to insertion, the Scan method requires the target variables to be of an appropriate type. This again aims to be flexible, with types converted where possible, provided no precision loss is possible, e.g., the above example shows a UUID column being read into a string variable. For a full list of supported go types for each Column type, see Type Conversions.
Finally, note the ability to pass a Context to the Query and QueryRow methods. This can be used for query level settings - see Using Context for further details.
Async insert
Asynchronous inserts are supported through the Async method. This allows the user to specify whether the client should wait for the server to complete the insert or respond once the data has been received. This effectively controls the parameter wait_for_async_insert.Columnar insert
Inserts can be inserted in column format. This can provide performance benefits if the data is already orientated in this structure by avoiding the need to pivot to rows.Using structs
For users, Golang structs provide a logical representation of a row of data in ClickHouse. To assist with this, the native interface provides several convenient functions.Select with serialize
The Select method allows a set of response rows to be marshaled into a slice of structs with a single invocation.Scan struct
ScanStruct allows the marshaling of a single Row from a query into a struct.
Append struct
AppendStruct allows a struct to be appended to an existing batch and interpreted as a complete row. This requires the columns of the struct to align in both name and type with the table. While all columns must have an equivalent struct field, some struct fields may not have an equivalent column representation. These will simply be ignored.
Parameter binding
The client supports parameter binding for theExec, Query, and QueryRow methods. As shown in the example below, this is supported using named, numbered, and positional parameters. We provide examples of these below.
Special cases
By default, slices will be unfolded into a comma-separated list of values if passed as a parameter to a query. If you require a set of values to be injected with wrapping[ ], ArraySet should be used.
If groups/tuples are required, with wrapping ( ) e.g., for use with IN operators, you can use a GroupSet. This is particularly useful for cases where multiple groups are required, as shown in the example below.
Finally, DateTime64 fields require precision in order to ensure parameters are rendered appropriately. The precision level for the field is unknown by the client, however, so the user must provide it. To facilitate this, we provide the DateNamed parameter.
Using context
Go contexts provide a means of passing deadlines, cancellation signals, and other request-scoped values across API boundaries. All methods on a connection accept a context as their first variable. While previous examples used context.Background(), you can use this capability to pass settings and deadlines and to cancel queries. Passing a context createdwithDeadline allows execution time limits to be placed on queries. Note this is an absolute time and expiry will only release the connection and send a cancel signal to ClickHouse. WithCancel can alternatively be used to cancel a query explicitly.
The helpers clickhouse.WithQueryID and clickhouse.WithQuotaKey allow a query id and quota key to be specified. Query ids can be useful for tracking queries in logs and for cancellation purposes. A quota key can be used to impose limits on ClickHouse usage based on a unique key value - see Quotas Management for further details.
You can also use the context to ensure a setting is only applied for a specific query - rather than for the entire connection, as shown in Connection Settings.
Finally, you can control the size of the block buffer via the clickhouse.WithBlockSize. This overrides the connection level setting BlockBufferSize and controls the maximum number of blocks that are decoded and held in memory at any time. Larger values potentially mean more parallelization at the expense of memory.
Examples of the above are shown below.
Progress, profile and log information
Progress, Profile, and Log information can be requested on queries. Progress information will report statistics on the number of rows and bytes that have been read and processed in ClickHouse. Conversely, Profile information provides a summary of data returned to the client, including totals of bytes (uncompressed), rows, and blocks. Finally, log information provides statistics on threads, e.g., memory usage and data speed. Obtaining this information requires the user to use Context, to which the user can pass call-back functions.Dynamic scanning
You may need to read tables for which they don’t know the schema or type of the fields being returned. This is common in cases where ad-hoc data analysis is performed or generic tooling is written. To achieve this, column-type information is available on query responses. This can be used with Go reflection to create runtime instances of correctly typed variables which can be passed to Scan.External tables
External tables allow the client to send data to ClickHouse, with a SELECT query. This data is put in a temporary table and can be used in the query itself for evaluation. To send external data to the client with a query, the user must build an external table viaext.NewTable before passing this via the context.
Open telemetry
ClickHouse supports trace context propagation on both TCP and HTTP transports. When using TCP, the client serializes the span into the native binary protocol. Useclickhouse.WithSpan to attach a span to a query via the context.
HTTP transport limitationWhile ClickHouse server accepts the standard
traceparent / tracestate HTTP headers, the clickhouse-go HTTP transport does not currently send them — WithSpan has no effect over HTTP. As a workaround, you can set the header manually via HttpHeaders in the connection options.