接続
以下の例では server のバージョンを返し、ClickHouse への接続方法を示しています。ここでは、ClickHouse が保護されておらず、default user でアクセスできることを前提としています。 接続には、デフォルトの ネイティブ ポートを使用している点に注意してください。conn 変数は作成済みで利用可能であると仮定します。
実行
任意のステートメントは、Exec メソッドで実行できます。これは、DDL や単純なステートメントに適しています。大規模な insert やクエリの反復処理には使用しないでください。
バッチ挿入
大量の行を insert する場合、クライアントはバッチ処理の仕組みを提供しています。これには、行を追加していけるバッチを準備する必要があります。最後に、それをSend() メソッドで送信します。バッチは、Send が実行されるまでメモリ上に保持されます。
接続リークを防ぐため、バッチに対して Close を呼び出すことを推奨します。これは、バッチの準備後に defer キーワードを使って行えます。これにより、Send が一度も呼び出されなかった場合でも接続がクリーンアップされます。行が 1 つも追加されなかった場合、クエリログに 0 行の insert が記録される点に注意してください。
エフェメラルカラム
エフェメラルカラムは書き込み専用のカラムで、挿入時にのみ存在します。保存されず、選択することもできません。挿入時に派生カラムの値を計算する際に便利です。行のクエリ
QueryRow メソッドを使って単一の行をクエリすることも、Query で結果セットを反復処理するためのカーソルを取得することもできます。前者では読み出したデータの格納先となる宛先を渡せますが、後者では各行に対して Scan を呼び出す必要があります。
SELECT ステートメントで指定した順序どおりに渡す必要があります。上記のように SELECT * を使用した場合は、デフォルトでカラム宣言順が使われます。
挿入時と同様に、Scan メソッドでも対象の変数には適切な型が必要です。ここでも柔軟性を重視しており、精度が失われない場合は可能な範囲で型変換が行われます。たとえば、上記の例では UUID カラムを string 型の変数に読み込んでいます。各カラム型でサポートされる Go の型の一覧については、型変換 を参照してください。
最後に、Query メソッドと QueryRow メソッドには Context を渡せる点にも注意してください。これはクエリレベルの設定に使用できます。詳細は Using Context を参照してください。
非同期 INSERT
非同期挿入は、Async メソッドでサポートされています。これにより、クライアントがサーバーでの挿入完了を待つか、データを受信した時点で応答を返すかを指定できます。これは実質的に、wait_for_async_insert パラメータを制御するものです。列指向での挿入
挿入はカラム形式でも行えます。データがすでにこの構造になっている場合は、行形式へ変換する必要がないため、パフォーマンス上のメリットがあります。構造体の利用
Golang の構造体は、ClickHouse のデータの 1 行を論理的に表現するのに役立ちます。そのため、ネイティブインターフェイスには便利な関数がいくつか用意されています。serialize を使用する Select
Select メソッドを使うと、1 回の呼び出しで、レスポンスとして返される複数の行を struct のスライスにマーシャリングできます。struct へのスキャン
ScanStruct を使用すると、クエリの単一の行を struct にマーシャリングできます。
struct の追加
AppendStruct を使用すると、既存のバッチに struct を追加し、それを完全な1行として解釈できます。これには、struct のカラム名と型がテーブルと一致している必要があります。すべてのカラムに対応する struct フィールドが必要ですが、一部の struct フィールドには対応するカラムがなくてもかまいません。その場合は単に無視されます。
サーバー側クエリパラメータ
ClickHouseのサーバー側クエリパラメータでは、{name:Type} 形式の型付きプレースホルダーを使用します。クエリとパラメータの値は別々に送信されるため、パラメータの値がSQLテキストに埋め込まれることはありません。
ClickHouse APIの場合は、クエリコンテキストを介してパラメータを渡します。
clickhouse.Named を使用して値を指定することもできます。
clickhouse.Named は、クライアント側の @name バインド構文でも使用できます。どちらの仕組みが使われるかは、クエリ内のプレースホルダー ({name:Type} または @name) によって決まります。
String 値とエスケープシーケンス
文字列値がどのように解釈されるかは、値の渡し方によって異なります。string/*string または []byte/*[]byte の値を指定した clickhouse.Named(または sql.Named) では、Go の値がそのままリテラルのパラメータ値として扱われます。制御文字はドライバーが自動的にエスケープするため、どちらのプロトコルでも値はバイト単位で正確に往復変換されます。値に実際の改行やタブが含まれていても問題ありません。
clickhouse.Parameters / WithParameters には、常に ClickHouse の Escaped フォーマットでシリアル化済みのパラメータテキストを指定します。自動ではエスケープされません。ClickHouse はパラメータをパースする際に、バックスラッシュによるエスケープシーケンスをデコードします。対象は \n (改行) 、\t (タブ) 、\r (キャリッジリターン) 、\0 (ヌルバイト) 、\\ (バックスラッシュそのもの) です。\N は、nullable 型において値全体が NULL であることを示すマーカーです。
Go の解釈付き文字列リテラル ("...") は clickhouse-go に渡される前に Go 自身によって処理されますが、生文字列リテラル (`...`) ではバックスラッシュがそのまま保持されます。Parameters では、パラメータテキストを次のように記述してください。
Parameters を構築する際に "line 1\nline 2" や "column 1\tcolumn 2" を使用しないでください。これらの Go リテラルには、すでに実際の改行やタブが含まれています。ClickHouse の Escaped フォーマットでは、実際の改行やタブのバイトはフィールドの区切りとして扱われるため、パラメータを完全にパースできず、サーバーによって拒否されます。Go の文字列をリテラル値として扱いたい場合は、代わりに Named を使用してください。
パラメータ値は SQL リテラルではありません。Named でトップレベルの String を渡す場合は、SQL の引用符を付けずに値を渡してください。'hello' ではなく hello とします。引用符を付けると、その文字自体が値の一部になってしまうためです。一方、複合型ではそのテキスト構文をそのまま使用します。例えば Array(String) であれば ['a', 'b'] となり、テキストにバックスラッシュによるエスケープや生の制御文字が含まれていない限り、Named で渡すこともできます。ネストされた文字列値のために複合型のテキストで \' エスケープシーケンスが必要な場合は、代わりに Parameters で渡してください。
ネイティブ API の完全な例
パラメータバインド
クライアントは、Exec、Query、QueryRow の各メソッドでパラメータバインドをサポートしています。以下の例に示すように、名前付きパラメータ、番号付きパラメータ、位置指定パラメータを利用できます。それぞれの例を以下に示します。
特殊なケース
デフォルトでは、スライスをクエリのパラメータとして渡すと、カンマ区切りの値のリストに展開されます。[ ] で囲まれた値のセットを挿入する必要がある場合は、ArraySet を使用します。
グループ/タプルが必要な場合は、たとえば IN 演算子で使うような ( ) で囲まれた値には、GroupSet を使用できます。これは、以下の例のように複数のグループが必要な場合に特に便利です。
最後に、DateTime64 フィールドでは、パラメータが適切にレンダリングされるよう、精度の指定が必要です。ただし、フィールドの精度レベルはクライアント側では分からないため、ユーザーが指定する必要があります。これを簡単にするために、DateNamed パラメータを用意しています。
コンテキストの使用
Go の コンテキスト は、期限、キャンセルシグナル、その他のリクエストスコープの値を API の境界をまたいで受け渡すための仕組みです。connection 上のすべての method は、第1引数として コンテキスト を受け取ります。これまでの例ではcontext.Background() を使用していましたが、この仕組みを使えば、設定や期限を渡したり、クエリをキャンセルしたりできます。
withDeadline で作成した コンテキスト を渡すと、クエリの実行時間に上限を設定できます。これは絶対時刻であり、期限が切れても行われるのは connection の解放と ClickHouse へのキャンセルシグナル送信だけである点に注意してください。代わりに WithCancel を使って、クエリを明示的にキャンセルすることもできます。
ヘルパーの clickhouse.WithQueryID と clickhouse.WithQuotaKey を使うと、クエリ ID とクォータキーを指定できます。クエリ ID は、ログでクエリを追跡したり、キャンセルしたりする際に役立ちます。クォータキーは、一意のキー値に基づいて ClickHouse の使用量に制限を課すために使用できます。詳しくは Quotas Management を参照してください。
また、Connection Settings に示されているように connection 全体に適用するのではなく、特定のクエリに対してのみ設定が適用されるように、コンテキスト を使うこともできます。
最後に、clickhouse.WithBlockSize を使ってブロックバッファのサイズを制御できます。これは connection レベルの設定 BlockBufferSize を上書きし、任意の時点でデコードされてメモリ上に保持されるブロックの最大数を制御します。値を大きくすると、メモリ使用量との引き換えに、より高い並列化が期待できます。
上記の例を以下に示します。
Progress、profile、log 情報
クエリでは、Progress、Profile、Log の情報を要求できます。Progress 情報では、ClickHouse で読み取りおよび処理された行数とバイト数の統計が報告されます。一方、Profile 情報では、クライアントに返されたデータの要約として、バイト数 (非圧縮) 、行数、ブロック数の合計が提供されます。最後に、Log 情報では、スレッドに関する統計 (メモリ使用量やデータ処理速度など) が提供されます。 この情報を取得するには、ユーザーがコールバック関数を渡せる Context を使用する必要があります。動的スキャン
返されるフィールドのスキーマや型が不明なテーブルを読み取る必要がある場合があります。これは、アドホックなデータ分析を行う場合や、汎用的なツールを作成する場合によくあります。これを実現するために、クエリのレスポンスではカラムの型情報を利用できます。これを Go のリフレクションと組み合わせることで、適切な型の変数のランタイムインスタンスを作成し、Scan に渡すことができます。外部テーブル
外部テーブル を使用すると、クライアントはSELECT クエリとともにデータを ClickHouse に送信できます。このデータは一時テーブルに格納され、クエリの評価時にクエリ内で利用できます。
クエリとともにクライアントから外部データを送信するには、ユーザーはまず ext.NewTable で外部テーブルを作成し、その後それを コンテキスト 経由で渡す必要があります。
OpenTelemetry
ClickHouse は、TCP と HTTP の両方のトランスポートで トレースコンテキストの伝播 をサポートしています。TCP を使用する場合、クライアントはスパンをネイティブバイナリプロトコルにシリアライズします。clickhouse.WithSpan を使用すると、コンテキスト経由でスパンをクエリに関連付けることができます。
HTTP トランスポートの制限ClickHouse server は標準の
traceparent / tracestate HTTP ヘッダーを受け付けますが、clickhouse-go の HTTP トランスポートは現在それらを送信しないため、HTTP では WithSpan は効果がありません。回避策として、接続オプションの HttpHeaders を使ってヘッダーを手動で設定できます。