Skip to main content

実験段階

ネイティブ TCP クライアント API は実験段階です。公開 API の仕様は、今後のリリースで変更される可能性があります。
メインクライアント、データソース、session、操作インターフェイス、および依存性注入の拡張機能を使用すると、 コンパイラ警告 CHTCP0001 が出ます。API の評価中にこの警告を許容するには、 プロジェクトファイルの NoWarn に追加してください。
APIを使用するコードは、将来の リリースで変更が必要になる可能性があると理解したうえでのみ、警告を抑制してください。

サポート対象の .NET バージョン

ネイティブ TCP クライアントは、以下の .NET バージョンをサポートしています。
  • .NET 8.0
  • .NET 9.0
  • .NET 10.0

サポート対象のClickHouseバージョン

TCPクライアントは、ClickHouseサーバーの最新のLTSバージョン2つと、直近のリリース3つを公式にサポートしています。

インストール

ネイティブ TCP クライアントは ClickHouse.Driver パッケージに含まれています。NuGet からインストールしてください。
または、NuGet パッケージ マネージャーを使用する場合:

クイックスタート

HTTP クライアントからの移行

TCP API は IClickHouseClient とは独立しており、 ClickHouseClient や ClickHouseConnection の通信方式を切り替えるオプションではありません。SQL の大部分は再利用できますが、 ClickHouseTcpClient を作成し、各操作を対応する TCP 操作に移行してください。

メソッドの対応関係

たとえば、HTTP クライアントで結果を読み取るループは次のようになります。
非同期 TCP 行ストリームになります:

オプションとパラメータ

HTTP の QueryOptions と ClickHouseParameterCollection は、対応する TCP のものと置き換えて使うことはできません。 値を ClickHouseTcpQueryOptions に移してください。TCP では設定値を文字列として指定し、 パラメータはオプションオブジェクトに含めます。
TCP クライアントは ClickHouse ネイティブの {name:Type} プレースホルダーをサポートしていますが、 ADO.NET 形式の @name プレースホルダーは書き換えません。また、クエリ単位でのデータベース、ロール、Bearer トークン、カスタム ヘッダーの指定や、パラメータリゾルバ、フォーマッタ、読み取りコンバーターにも対応していません。HTTP クライアントでのみ利用できる 機能については、制限事項を参照してください。

接続と結果のライフタイム

どちらの高レベルクライアントもスレッドセーフなので、再利用してください。TCP クライアントは HTTP 接続ではなく、永続的なネイティブ接続を 保持します。IAsyncDisposable を実装しているため、通常はアプリケーションの終了時に非同期で破棄してください。 QueryAsync が返す行は呼び出し元が所有します。一方、StreamAsync が返すブロックとそのカラムは借用データであり、 現在の反復中にしか有効ではありません。反復後も必要な値はコピーしてください。接続がプールに戻るよう、列挙は必ず最後まで実行するか、 破棄してください。複数の操作を同じ接続で実行し、セッション状態を維持する必要がある場合は、 OpenSessionAsync を使用してください。 両方のクライアントを同じテーブルに対して使用する方法については、完全な HTTP から TCP への移行例 を参照してください。

設定

ネイティブ TCP クライアントを設定する方法は 2 つあります。
  • 接続文字列: サーバーのエンドポイント、 認証情報、その他の接続オプションを指定する、セミコロン区切りのキーと値のペアです。
  • ClickHouseTcpClientOptions オブジェクト: コード内で設定する、厳密に型付けされたイミュータブルな 設定オブジェクトです。
どちらの形式も ClickHouseTcpClient コンストラクターに渡して使用します。 ClickHouseTcpConnectionStringBuilder を使用すると、接続文字列のパースや構築を行い、 ClickHouseTcpClientOptions に変換できます。
以下のセクションでは、利用可能な設定とそのデフォルト値、および各設定が及ぼす影響を一覧にまとめます。

接続設定

TimeSpan プロパティの接続文字列では、値を秒単位で指定します。

データフォーマットとシリアライゼーション

接続プーリング

1 つの接続で一度に実行できる操作は 1 つだけです。接続プールを使うと、複数の操作を同時に実行でき、 操作間で接続を再利用できます。

セキュリティ

TLS を使用しない場合、パスワードとすべてのクエリデータは暗号化されずにネットワーク上を送信されます。ローカル開発以外では TlsAllowInvalidCertificates を false に設定したままにしてください。
TLS 対応のネイティブプロトコルは、通信中に TLS へ切り替える方式ではなく、独立したサーバーのエンドポイントを使用します。TLS クライアントはセキュアなネイティブプロトコル用ポートに接続する必要があり、平文通信にはフォールバックしません。ConfigureTls は 最後に適用され、証明書とホスト名の検証設定を上書きできるため、カスタムコールバックは 慎重に確認してください。

ロギングとデバッグ

クライアントのロガーは、クライアント側のライフサイクルイベントと操作イベントを記録します。一方、サーバーのログパケットは ClickHouseTcpQueryCallbacks.OnLog に送信されます。ステートメントのテキストには機密データが含まれる可能性があるため、 デフォルトではアクティビティタグに含めず、デバッグログでは大幅に切り詰めます。

カスタム設定

ClickHouseTcpClientOptions.CustomSettings は、すべてのクエリと 挿入処理に ClickHouseサーバーの設定を適用します。操作ごとの ClickHouseTcpQueryOptions.Settings に設定した値は、 同じ名前のクライアント全体に適用される値よりも優先されます。
接続文字列では、各サーバー設定の先頭に set_ を付けます。
CustomSettings または操作ごとの Settings に設定を追加する際は、set_ プレフィックスを付けないでください。

ClickHouseTcpQueryOptions

ClickHouseTcpQueryOptions は、操作ごとの設定を指定します。プロパティはすべて任意です。

ClickHouseTcpInsertOptions

ClickHouseTcpInsertOptions は ClickHouseTcpQueryOptions を拡張し、ネイティブ形式でのブロック挿入に関する設定を追加します。 クエリオプションのプロパティもすべて使用できます。

ClickHouseTcpClient

ClickHouseTcpClient はネイティブ TCP プロトコル用の高水準 API です。ステートメントや スカラ―クエリを実行し、結果を列指向ブロック、行、または POCO としてストリーミングします。また、列指向データや行データを挿入し、 特定の接続に固定された session を開くこともできます。 このクライアントはスレッドセーフで、接続プールを管理します。エンドポイントごとにクライアントを 1 つ作成し、アプリケーション全体で共有して、 シャットダウン時に破棄してください。操作は MaxPoolSize を上限に同時実行されます。上限を超えた 操作は、接続が空くまで最大 PoolTimeout の間待機します。

クライアントの作成

接続文字列または ClickHouseTcpClientOptions を使用してクライアントを作成します。指定できる設定については、 設定を参照してください。 接続文字列を使用する場合:
厳密な型が指定されたオプションを使用する場合:
非同期で破棄することを推奨します。クライアントを破棄すると、アイドル状態の接続を閉じ、実行中の操作が完了するまで最大 PoolTimeout 待機した後、完了しなかった操作を中断します。

依存性注入

AddClickHouseTcpDataSource はシングルトンのデータソースを 1 つ登録し、その共有クライアントを IClickHouseTcpClient および IClickHouseTcpOperations として公開します。
サービスプロバイダーがデータソースと接続プールを管理します。依存性注入されたクライアントは破棄せず、 アプリケーションの終了時にサービスプロバイダーを破棄してください。オプションで LoggerFactory を指定しない場合、 登録にはコンテナーの ILoggerFactory が使用されます。serviceKey を使用すると、複数の 独立したデータソースを登録できます。

クエリの実行

DDL やミューテーションなど、行を返さないステートメントの実行には ExecuteAsync を使用します。
このメソッドは、サーバーがステートメントを受け付けた時点で完了します。ステートメントが行を返す場合、 ExecuteAsync はその行を読み取って破棄します。 INSERT INTO ... VALUES では、InsertAsync または InsertRowsAsync を使用し、SQL ステートメントには 値を直接記述せず、VALUES で終えてください。

データの読み取り

アプリケーションで必要な結果の形式に応じて、読み取り API を選択します。

スカラー値の読み取り

ExecuteScalarAsync は、最初の行の最初のカラムの値を object として返します。
このメソッドはレスポンス全体を読み取り、最初の値以外は破棄します。大量の結果を途中で打ち切るために使うのではなく、 1 行だけを返すクエリを記述してください。最初の値が NULL の場合も、クエリが 行を返さない場合も、null が返されます。

行単位の読み取り

QueryAsync は、結果のカラム順に値を格納した各行固有の object[] をストリーミングします。
行を表す配列は、列挙が進んだ後も有効です。この方式は結果 モデルがない場合に便利ですが、行ごとに配列を1つ割り当て、値型をボックス化します。

POCO への読み取り

QueryAsync<T> は、カラムを public な setter を持つプロパティにマッピングします。名前の照合では大文字・小文字や アンダースコアの有無を区別しません。名前を明示的に指定するには ClickHouseTcpColumn を、プロパティを マッピング対象から除外するには ClickHouseTcpNotMapped を使用します。
POCO マッピングでは、データを変換し、行ごとに 1 つのオブジェクトを割り当てます。

列指向ブロックの読み取り

StreamAsync は、ネイティブの列指向の結果を Block 値の連続として返します。データを読み取る最も高速な方法です。
ブロックは借用されるものです。ブロック、そのカラム、および各カラムの値のスパンが有効なのは、現在の 反復中だけです。これらを破棄したり保持したりしないでください。ループ本体の処理後も必要なデータは、自分で管理するメモリに明示的にコピーしてください。
接続がプールに戻るよう、必ず列挙を最後まで行うか、列挙子を破棄してください。
Block.Column<T> では、デコーダが生成した CLR 型の値にアクセスできます。型変換が必要な場合は Block.ReadAs<T> または IDateTimeColumn などの専用インターフェイスを使用してください。

データの挿入

ネイティブ insert では、データを列指向の wire ブロックとして送信します。SQL には、値をインラインで列挙しない INSERT INTO ... VALUES ステートメントを指定してください。クライアント側の処理を最小限に抑えるには型付きカラムを使用します。アプリケーションがすでに行指向のデータを保持している場合は、行または POCO のオーバーロードを使用してください。

列指向の挿入

InsertAsync は、型付きカラムごとにあらかじめまとめられたデータを受け取ります。データを挿入する方法としては、これが最も高速です。
カラムは引数の順序ではなく名前でSQLのカラムリストと照合され、行数も一致している必要があります。ステートメントで省略されたテーブルのカラムには、サーバーがデフォルト値を設定します。挿入が完了するまで、呼び出し元が所有する配列を変更しないでください。 このAPIを使用すると、行単位の挿入で必要になる行からカラムへの変換や値型のボックス化を避けられます。借用した結果ブロックから読み取ったカラムも、そのブロックが解放される前に挿入が完了するのであれば、InsertAsyncに直接渡せます。

行の挿入

InsertRowsAsync は object[] 型の行を受け取ります。各値は SQL のカラムリストに記載された順序でカラムに対応します。
行はブロック単位でカラムに変換されます。各行には、ステートメントで指定されたカラムごとに値を1つ含める必要があります。 また、対象のカラムが Variant または Dynamic の場合を除き、同じカラムの値はすべて同じ CLR 型にする必要があります。 操作が完了するまで、行を変更しないでください。

POCO を使用した挿入

ジェネリック版の InsertRowsAsync<T> オーバーロードは、POCO の読み取り時と同じ命名規則と属性に関する規則に従い、挿入先のカラムを読み取り可能な public プロパティに対応付けます。
ステートメントで指定したすべてのカラムに、互換性のある public な getter が対応している必要があります。POCO の行は wire ブロックごとに変換されるため、後続のブロックに無効な値があっても、 先行するブロックの送信後に初めて検出されることがあります。ClickHouseTcpNotMapped を使用すると、 ImportBatch などのアプリケーション専用プロパティをマッピング対象から除外できます。

SQL パラメータ

ネイティブクライアントは、ClickHouse ネイティブの {name:Type} プレースホルダーに値をバインドします。 ADO.NET 形式の @name プレースホルダーは書き換えません。
各パラメータの型は、SQL のプレースホルダーまたは ClickHouseTcpParameter.ClickHouseType プロパティで指定する必要があります。テーブル名とカラム名には Identifier 型を 使用してください。DateTime または DateTimeOffset が特定の時点を表す場合は、 {timestamp:DateTime('UTC')} のようにタイムゾーンを指定してください。指定しないと、サーバーの session のタイムゾーンによって解釈が変わる可能性があります。

クエリ ID

各操作には、ClickHouse のシステムテーブル、クライアントログ、トレーススパンで使用されるクエリ ID が割り当てられます。 QueryId が null または空の場合、クライアントは新しい GUID を生成します。操作をアプリケーションの識別子と 相関付ける必要がある場合は、QueryId を設定してください。

クエリの進捗状況とメタデータ

レスポンスの途中に挟まれて送られるメタデータを受け取るには、ClickHouseTcpQueryOptions.Callbacks を設定します。
Progress の値は累計ではなく増分です。コールバックはレスポンスを読み取る スレッド上でパケット順に同期実行されるため、処理を速やかに終え、例外をスローしないようにしてください。OnLog、 OnProfileEvents、OnTotals、OnExtremes に渡されるブロックは借用したものであり、 コールバックの外に持ち出してはいけません。 ClickHouse は、挿入でアップロードされた行について、クエリの進捗パケットを送信しません。 クライアントが送信したブロックを監視するには OnBlockWritten を使用してください。報告されるのは転送の進捗であり、 サーバーが挿入をコミットしたことを示すものではありません。

キャンセル

すべての操作で CancellationToken を指定できます。
ストリーミング結果の取得をキャンセルしたり途中でやめたりすると、その接続は安全に再利用できなくなるため、クライアントは プールに戻さずに接続を閉じます。クライアント自体は引き続き使用でき、後続の操作では別の接続を 開くか、既存の接続を再利用します。特定の接続に固定された session では、キャンセルによって session が終了し、一時テーブルや設定が失われる場合があります。

サーバー情報とヘルスチェック

GetServerInfoAsync は、ネイティブのハンドシェイクで得られたサーバーのアイデンティティ、バージョン、タイムゾーン、およびネゴシエーション済みのプロトコル情報を返します。
wire レベルの機能は、クライアントとサーバー間でネゴシエートされたリビジョン ProtocolRevision に基づいて 利用可否を判定します。データ型や関数などの SQL 機能は Version に基づいて判定します。このメソッドは、利用可能な 接続があれば再利用し、プールが空の場合は新しい接続を開きます。 ネイティブプロトコル経由のレディネスチェックには PingAsync を使用します。
Ping に成功すると、ネイティブ接続と認証が正常に機能していることを確認できます。ただし、アプリケーションの テーブルにアクセスできるかどうかは確認できません。

その他の例

読み取り、データの挿入、データ型、セッション、TLS、オブザーバビリティ、 エラー処理を網羅した、そのまま実行できる例については、 GitHub リポジトリにある ネイティブ TCP の例を参照してください。

session

通常のクライアント操作では、プール内の利用可能な接続が使用されるため、接続固有の状態は 操作ごとに分離されず、呼び出し間で保持される保証もありません。プール内の接続は、それぞれ異なるサーバーにつながっている場合があります。 一時テーブル、SET ステートメント、または一連の操作で同じ接続を使う必要がある場合は、session を開いてください。
IClickHouseTcpSession は、クライアントと同じクエリ、実行、挿入、ping、サーバー情報の API を提供します。 sessionはスレッドセーフではありません。操作は逐次実行され、現在の操作が 完了する前に次の操作を開始しようとすると拒否されます。ストリーミングされる結果を取得した場合、最後まで列挙するか、 列挙子を破棄するまで、sessionは使用中のままです。 各sessionは、存続期間中、MaxPoolSize のスロットを 1 つ占有します。クライアントは プール内のほかの接続を引き続き使用できますが、プールに接続が 1 つしかない場合、ほかのクライアント操作は sessionが破棄されるか、PoolTimeout によってタイムアウトするまで待機します。 親クライアントを破棄する前に、sessionを破棄してください。sessionを破棄すると、session専用の 接続はプールに戻されずに閉じられます。これにより、後続の呼び出し元にそのsessionの 一時テーブルや設定が引き継がれるのを防げます。接続やプロトコルの障害、キャンセル、結果ストリームの読み取りが完了していないことによって sessionが使用できなくなる場合があります。IsOpen が false になったら、新しいsessionを開いてください。

ベストプラクティス

クライアントのライフサイクルと接続プール

エンドポイントと設定の組み合わせごとに ClickHouseTcpClient または ClickHouseTcpDataSource を1つ作成し、 アプリケーションの稼働中は再利用してください。クライアントはスレッドセーフで、 自身の接続プールを管理します。操作のたびにクライアントを作成すると、その都度新しいプールが作られ、接続を 再利用できなくなります。 依存性注入を使用するアプリケーションでは、AddClickHouseTcpDataSource を一度だけ登録し、 IClickHouseTcpClient を注入してください。クライアントはサービスプロバイダーが管理するため、 注入されたインスタンスを利用側で破棄しないでください。依存性注入を使用しない場合は、await using を使ってアプリケーションの終了時にクライアントを破棄してください。 1つのネイティブ接続で同時に実行できる操作は1つだけです。そのため、MaxPoolSize は開いている 接続数と同時実行できる操作数の両方を制限します。接続を取得できなかった呼び出し元は、空きが出るまで最大 PoolTimeout の間待機します。 サーバー側の接続数とクエリ数の上限を超えずに、アプリケーションで実際に必要な同時実行数を 確保できる値を選んでください。値を増やしても、個々のクエリが速くなるわけではありません。 次の処理もプールの接続を使用する点に注意してください。
  • ストリーミング結果は、列挙子が破棄されるまで接続を保持します。
  • sessionは、その存続期間を通じて1つの接続を保持し、一度に1つの操作だけを 受け付けます。
  • 結果の取得を途中でやめた場合、実行中の操作をキャンセルした場合、またはプロトコルや接続に障害が発生した場合、 接続は再利用されずに閉じられます。
sessionは速やかに破棄し、非同期結果は必ず最後まで列挙するか、列挙子を破棄してください。 プールの枯渇、予期しない接続の終了、頻繁な再接続の原因を調べるには、ClickHouse.Driver.Tcp.Pool ログカテゴリを使用してください。

タイムアウトとキャンセル

TCP クライアントでは、待機の種類ごとに異なる制限が適用されます。 プールのスロットが空くのを待ってから接続を開くチェックアウトには、最大で PoolTimeout + DialTimeout かかることがあります。ReadTimeout は転送層での読み取りごとにリセットされるため、 進捗情報やデータを送り続ける長時間のクエリは、その設定値を超えて実行される場合があります。通常の処理で サーバーからの応答が途絶える時間を考慮し、十分に大きな値を設定してください。TimeSpan.Zero に設定するのは、別のタイムアウトによって操作時間を確実に制限できる場合だけにしてください。 操作全体に適用するタイムアウトが必要な場合は、キャンセルトークンを使用します。
クライアントは、安全に送信できる場合、ネイティブのCancelパケットの送信を試みます。その後、応答を最後まで読み出せなかった 接続を閉じます。プール内のクライアントはその後も 操作できますが、キャンセルによって特定の接続に固定されたsessionが使用できなくなる場合があります。キャンセルされた、またはタイムアウトした挿入は 実行結果が不明な場合があります。むやみに再実行せず、挿入の再試行に関するガイダンスに従ってください。

日付と時刻の扱い

タイムスタンプには DateTime('UTC') または DateTime64(S, 'UTC') を優先し、アプリケーションコードでは DateTimeOffset または Kind が Utc の DateTime を使用してください。これにより、表している時点が明確になり、 サーバーや session のタイムゾーンに依存せずに済みます。 TCP クライアントは、DateTime 値を書き込む際に次の規則を適用します。 夏時間への切り替えで飛ばされる時刻を指定すると、対応する時点が存在しないため拒否されます。標準時に戻る際に重複する時刻については、先に現れる時点が選択されます。どちらの時点かを明示する必要がある場合は、DateTimeOffset を使用してください。 特定の時点を表す SQL パラメータには、タイムゾーンを含むプレースホルダーを使用してください:
列指向で読み取る場合、DateTime と DateTime64 はデフォルトで生の uint または long のカウント値として取得されます。 暦上の日時として扱いたい場合は、Block.ReadAs<DateTimeOffset>、IDateTimeColumn.GetDateTimeOffset、または対応する POCO プロパティを使用してください。 すべての桁を保持する必要がある場合は、生のカウント値をそのまま使用してください。 DateTimeOffset の分解能は 100 ナノ秒のため、スケールが 8 または 9 の DateTime64 をこれらの方法で読み取ると、 ティック未満の精度が失われます。 Date と Date32 には DateOnly を使用してください。負の値や 24 時間を超える値を取り得る Time と Time64 には、 TimeSpan を使用してください。TimeOnly は、カラムの値が一日の時刻に制限されている場合にのみ適しています。

ストリーミングと結果の有効期間

高スループットの処理にはStreamAsyncと型付きカラムを使用してください。ClickHouseの 列指向のデータ配置に沿った方法で、行ごとの配列やボックス化、POCOの割り当てを回避できます。割り当てを最小限に抑えることよりも アプリケーション側で所有するモデルを重視する場合はQueryAsync<T>を使用し、型指定のない QueryAsyncはコンパイル時にスキーマが不明な場合にのみ使用してください。 StreamAsyncが返すブロックは借用したものです。ブロックとそのカラム、複合型の子カラム、 すべてのスパンが有効なのは、現在のループの反復中だけです。その場で処理するか、反復後も 保持する必要がある値をコピーしてください。
列挙されたブロックを自分で破棄しないでください。列挙子の破棄は await foreach に任せてください。結果の一部だけが 必要な場合は、SQL の LIMIT で取得件数を制限し、必要なカラムだけを選択してください。途中でループを抜けると、 残りのレスポンスがキャンセルされ、その接続を再利用できなくなります。

挿入データの構造とバッチ処理

データがすでに列指向の場合は、型付きカラムを指定して InsertAsync を使用してください。クライアント側での 変換を最小限に抑えられます。POCO データには InsertRowsAsync<T> が適しています。型が指定されていない object[] の行は最も柔軟ですが、配列の割り当てと値型のボックス化が発生します。 小さな挿入を何度も実行するのではなく、1 回の挿入呼び出しで十分な数の行を送信してください。1 回の 呼び出し内で、MaxRowsPerBlock はデータをネイティブの wire ブロックに分割します。デフォルトの 50,000 行という値は、 行や POCO の入力を変換する際に使用する一時的なカラムバッファのサイズも制限します。この値を増やすと、 カラム数の少ない行ではスループットが向上する可能性がありますが、ピーク時のメモリ使用量も増加します。null に設定すると、挿入データ全体が 1 つのブロックとして書き込まれ、そのブロックに含まれる行指向の入力がまとめて変換されます。 MaxSendBufferBytes は、エンコード済みデータをソケットに書き出す前にバッファに保持できる量を、別途制限します。 これはカラムの境目でチェックされる緩やかな上限のため、サイズの大きいカラムが 1 つあるだけで超過することがあります。 行と POCO の入力はブロック単位で変換されます。そのため、後続のブロックに不正な値があっても、 先行するブロックの送信後まで検出されないことがあります。データ品質が不確かな場合は、 挿入前に null 許容性と CLR 型を検証し、論理バッチを再試行する可能性がある場合は必ず データに基づいて生成した DeduplicationToken を設定してください。

サポートされているデータ型

以下のテーブルでは、デコードされた IColumn<T> が返す型と、 Block.ReadAs<T> による変換、QueryAsync<T> の POCO マッピング、または挿入で利用できる追加の型を区別しています。特定のマッピングがサポートされているかどうかは、これらの操作で使われるのと同じ リゾルバに問い合わせて確認できます。
Nullable、Array、Tuple、Map、LowCardinality のマッピングは、それぞれの 内部型にも再帰的に適用されます。

型マッピング: ClickHouse からの読み取り

Default .NET type は、Block.Column<T> と IColumn<T> で公開される T を指します。 Also readable as カラムに記載された型は、Block.ReadAs<T> と POCO のプロパティでも使用できます。

整数型

浮動小数点型

Decimal 型

ClickHouseTcpDecimal は、任意の大きさの整数で表される仮数とスケールを格納し、decimal で扱える精度を超える値も 保持できます。

ブール値型

String 型

データが有効な UTF-8 ではない可能性がある場合は、IStringColumn.GetBytes(row) を使用するか、byte[] として読み取ってください。 FixedString(N) は、末尾のゼロバイトも含め、N バイトすべてを保持します。

日付と時刻の型

列指向で読み取る際に wire 上の値を正確に保持できるよう、既定では変換前の整数値として読み取ります。 日時への変換には、型で宣言されたタイムゾーンを使用します。型にタイムゾーンの指定がない場合は、 セッションのタイムゾーンを使用します。Time または Time64 を TimeOnly として読み取る場合、値が負か 24 時間以上であれば例外がスローされます。ClickHouse で扱える値の全範囲を読み取るには TimeSpan を使用してください。

Enum 型

IEnumColumn からは、宣言済みのラベルと序数の対応関係も取得できます。

その他のスカラー型

複合型

タプルには最大 7 個の要素を含められます。Nested カラムはフィールド数に依存しないため、 INestedColumn を使って読み取るのが最適です。これにより、ボックス化されたレコードを生成せずに、 名前付きのフラットなフィールドカラムと共通の行オフセットにアクセスできます。ClickHouse のデフォルト設定 flatten_nested = 1 では、ネストされたフィールドは代わりに ドットで区切られた個別の Array(T) カラムとして渡されます。

Variant、Dynamic、JSON 型

Variant と Dynamic は、各行で選択された型の CLR 値、または null を返します。これらの列指向ビューでは、判別子ストリームと、実行時の型ごとに型が明示された子カラムにアクセスできるため、カラム単位でのデータ処理時にボックス化を回避できます。 TCP クライアントは、ClickHouse の String シリアライゼーションを使用して JSON を読み取ります。クライアントはデフォルトで output_format_native_write_json_as_string = 1 を有効にします。この設定を無効にすると、JSON の読み取りはサポート対象外になります。ClickHouse は JSON をパースして正規化するため、返されるテキストは挿入したテキストとキーの順序、空白、数値のフォーマットが異なる場合があります。

ジオメトリ型

Geometry は、6 種類のジオメトリ型を格納する IVariantColumn として公開されます。

QBit 型

TCP クライアントは、引数が 2 つでストライドのない QBit(T, N) 形式に対応しています。引数が 3 つでストライドのある 形式には対応していません。

AggregateFunction 型

AggregateFunction カラムには、関数固有の中間状態が格納されています。たとえば sumMerge(column) を使ってサーバー側で最終的な値を算出し、その値を読み取ってください。

型マッピング: ClickHouse への書き込み

各エントリは、InsertAsync に渡す IColumn の 1 行分の CLR 型を表します。この型マッピングは 厳密で、TCP クライアントは Convert のような型変換を行いません。

整数型

浮動小数点型

BFloat16 への書き込み時には、各 float 値が 16 ビットの Brain Floating Point 形式に切り詰められます。

Decimal 型

スケーリング後の仮数が宣言された精度を超えると、書き込み時に OverflowException がスローされます。

ブール値型

String 型

FixedString(N) は仕様上、string を受け付けません。バイナリ表現が一意に定まるよう、値を明示的にエンコードし、 パディングしてください。

日付と時刻の型

整数を直接指定する場合は、読み取りの表に示した単位を使用します。DateTimeOffset では時点が保持されます。 DateTime は自身の Kind に従います。Unspecified の値は、カラムの タイムゾーンでの現地時刻として解釈されます。カラムにタイムゾーンが指定されていない場合は、セッションのタイムゾーンでの現地時刻として解釈されます。

Enum 型

未定義のラベルは、データの送信前に拒否されます。

その他のスカラー型

複合型

受け付けるデータの形は再帰的に決まるため、Array(Nullable(DateTime)) は各行の DateTime?[] を受け付け、 Map(String, UInt32) は KeyValuePair<string, uint>[] を受け付けます。 Nested に直接書き込む場合は、以前の読み取りで返された密なカラム構造を使用します。アプリケーション側で組み立てる 挿入データには、デフォルトの flatten_nested = 1 による表現を使用し、ドットで区切られた各 Array(T) フィールドを 個別のカラムとして書き込んでください。

Variant、Dynamic、JSON 型

Variant では、実行時の型がいずれかの代替型のデフォルトの CLR 型と一意に一致する必要があります。DateTime を DateTime の代替型に書き込む場合などに使える簡易マッピングは、Variant 内では適用されません。 代わりに、その代替型のデフォルトの raw 型を使用してください。Dynamic は、スカラー値に加え、再帰的にサポートされる配列、Map、タプルの値に対応しています。

ジオメトリ型

アプリケーション側で構築した Geometry カラムでは、Point と MultiPolygon だけが他と重複しない CLR のデータ構造を持ちます。 Ring と LineString、Polygon と MultiLineString はそれぞれ同じ構造を持つため、クライアントは object の値がどちらの型を表すのか推論できません。デコード済みの Geometry カラムには 判別子が保持されているため、型を判別できないという問題なく再挿入できます。

QBit 型

AggregateFunction 型

圧縮

クライアントはデフォルトで圧縮を有効にし、書き込むブロックに LZ4 を使用します。ClickHouse も応答ブロックにはデフォルトで LZ4 を使用します。圧縮は結果ブロックと挿入によってアップロードされるブロックに適用されます。一方、 クエリテキスト、進捗情報、例外、その他のプロトコルパケットは通常のワイヤエンコーディングのままです。 クライアントが使用するコーデックは、接続文字列の Compression キーで指定します。
これと同等の強い型付けを使用した設定では、IClickHouseCompressor を使用します。
圧縮を無効にするには、Compressor = null を設定します。カスタム圧縮器はネイティブのブロック フレーミングに対応している必要があります。HTTP ボディにしか対応していない圧縮器は、クライアントの作成時に受け付けられません。

レスポンス用コーデックの選択

Compressor は、クライアントが書き込むブロックの圧縮方法を決定します。ネイティブのクエリパケットは サーバーに圧縮を要求しますが、コーデックは指定しません。そのため、ClickHouse は network_compression_method 設定に基づいてレスポンス用のコーデックを選択します。サーバーのデフォルトは LZ4 です。 必要に応じて、操作ごとにレスポンス用のコーデックを設定します。
LZ4 は一般に CPU 使用量が少なく、高速なネットワークではデフォルトとして最適です。ZSTD は一般に、 CPU 使用量がやや増えるものの、フレームをより小さくできます。同じホスト上のサーバーや 非常に高速な接続先では、圧縮を無効にすることで性能が向上する場合があります。デフォルト設定を変更する前に、実際のデータに近いデータを使って性能を測定してください。

エラー処理

ClickHouse またはネイティブ接続で発生したエラーは、DbException を継承する ClickHouseTcpException の派生クラスとして報告されます。 ClickHouseTcpServerException には、サーバーから送信された数値コードそのものを示す RawCode と、 ドライバーで名称が定義されている場合に対応する ClickHouseErrorCode を示す Code があります。また、 サーバー側の例外の Name と ServerStackTrace を保持し、入れ子になったサーバー側の例外には InnerException からアクセスできます。
ClickHouseErrorCode に含まれないコードは Code == ClickHouseErrorCode.Unknown になります。enum に ClickHouse のすべてのエラーが含まれているとは限らないため、 RawCode を確認してください。 引数の検証エラーとオブジェクトのライフサイクルに関するエラーには、通常の .NET 例外型が使用されます。 キャンセル時には OperationCanceledException が送出されます。DialTimeout と ReadTimeout では、 内部例外として TimeoutException を含む ClickHouseTcpConnectionException が送出され、接続は破棄されます。 PoolTimeout では通常の TimeoutException が送出されます。これは ClickHouseTcpException ではありません。接続に 障害が発生したわけではないため、同時実行する操作を減らすか、プールを拡大するか、結果の列挙を完了してください。

操作の再試行

データの挿入中に接続障害やタイムアウトが発生した場合、挿入が成功したかどうかは分かりません。 クライアントが応答を受け取れなくなる前に、サーバーが行をコミットしていた可能性があります。再試行する前に、対象の論理バッチに対して変わらない DeduplicationToken を設定してください。
そのバッチを再試行する際は同じトークンを使い、新しいデータには別のトークンを使用してください。その他の 操作は、ステートメントを繰り返し実行しても安全で、発生した障害が一時的な場合にのみ再試行してください。 サーバーエラーのほとんどは、再試行ではなくクエリや設定の変更が必要です。

ロギングと診断

TCP クライアントは Microsoft.Extensions.Logging と連携します。ロギングは省略可能です。 LoggerFactory を指定しない場合、クライアントはロガーを作成せず、ログメッセージの整形も行いません。
依存性注入の拡張機能を使ってクライアントを登録した場合、指定したオプションで別の ILoggerFactory を設定していない限り、コンテナーの ILoggerFactory が使用されます。

ログのカテゴリ

標準の .NET ログ設定を使用して、これらのカテゴリを設定します。
操作開始メッセージは Debug レベルで記録され、SQL の先頭から最大 StatementMaxLength 文字が含まれます。 デフォルトは 5 文字です。ログにステートメントのテキストを含めない場合は値を 0 以下に設定してください。 値を増やす場合は、パラメータやリテラルに機密データが含まれる可能性を考慮したうえで行ってください。

サーバーのログメッセージ

ロギングインテグレーションは、クライアント側の動作を記録します。ClickHouse 独自のクエリログパケットは これとは別に ClickHouseTcpQueryCallbacks.OnLog に送られます。これらを有効にするには、 send_logs_level サーバー設定を使用します。
ログブロックは一時的に借用され、コールバックから戻ると解放されます。同期的に処理するか、 保持する必要がある値をコピーしておいてください。コールバックの処理は短時間で終わらせ、例外をスローしないでください。コールバックで例外が発生すると、 その操作と接続が終了します。

OpenTelemetry

TCP クライアントは、.NET’の System.Diagnostics.Activity API を使用して分散トレーシングのスパンを送出します。 OpenTelemetry のトレーサープロバイダーで TCP アクティビティソースを購読します。
コンソールアプリケーションまたは手動セットアップの場合:
アクティビティのソース名は ClickHouse.Driver.Tcp で、HTTP クライアントのソースとは異なるため、 どちらの通信方式も個別に収集できます。リスナーが購読していない場合は、操作を実行しても アクティビティは生成されません。

スパンと属性

クライアントは、SQL 操作、ping、新規接続についてスパンを出力します。SQL スパンには、 SELECT や INSERT など、ステートメントの先頭のキーワードに基づいて名前が付けられます。先頭のキーワードを 判別できないステートメントには query が使用されます。connect スパンには、ソケット接続、TLS ネゴシエーション、 ネイティブハンドシェイクが含まれます。ステートメントのスパンには、接続プールからの接続を待つ時間も含まれます。 カウンターは、サーバーまたはクライアントに報告できる意味のある値がある場合にのみ含まれます。たとえば、 ブロックをアップロードする挿入では、クライアントが送信した行数は報告されますが、 サーバーから読み取りカウンターは報告されません。失敗したスパンには、例外の型、メッセージ、スタック トレースを含む exception イベントも記録されます。

SQL テキストと機密データ

SQL テキストはデフォルトではスパンに含まれません。明示的に有効化し、適切な上限を設定してください。
StatementMaxLength は、db.query.text 属性とデバッグログに出力される SQL の両方の最大文字数を制限します。値が 0 以下の場合、SQL テキストはどちらにも出力されません。サーバーエラーにはクエリの詳細が含まれることがあるため、 エクスポートされる例外メッセージとスタックトレースも確認してください。

トレースコンテキストの伝播

Activity.Current が W3C ID フォーマットを使用している場合、クライアントはトレース ID、スパン ID、トレースフラグ、 トレースステートをネイティブの Query パケットに書き込みます。これにより、ClickHouse は同じ 分散トレースに属するサーバースパンを作成できます。サーバー側でのスパンの収集とサンプリングは、引き続き ClickHouse 構成で制御します。たとえば、 サンプリング確率はクエリごとに設定できます。
伝播されたクエリ ID をトレース ID と併用すると、クライアントスパンを system.query_log や、設定されている場合は ClickHouse の system.opentelemetry_span_log と相関付けることができます。

制限事項

TCP クライアントは実験的な機能であり、HTTP クライアントのすべての機能には対応していません。

HTTP でのみ利用できる機能

TCP API は ADO.NET プロバイダーではなく、ORM では使用できません。また、 CSV、JSONEachRow、Parquet、raw stream 形式の入出力、Bearer 認証、カスタム HTTP ヘッダー、カスタムのパラメータ型解決・フォーマット・読み取り時の変換、クエリごとのデータベース やロールの指定にも対応していません。アプリケーションでこれらの機能が必要な場合は、 HTTP クライアントを使用してください。

SQL パラメータ

サポートされるのは、ClickHouse ネイティブの {name:Type} プレースホルダーのみです。TCP クライアントは ADO.NET 形式の @name プレースホルダーを書き換えません。ClickHouse 25.8 から 26.6 では、limit や offset など、 サーバー設定と同じ名前のパラメータが設定として解釈され、拒否される場合があります。これらのバージョンに対応する場合は、 たとえば row_limit のようにパラメータ名を変更してください。

データ型の対応範囲

サポートされているデータ型のセクションに、データ型の対応関係をすべて記載しています。 現在のネイティブコーデックには、主に次の制約があります。
  • タプルに含められる要素は最大7個です。
  • AggregateFunction(function, ...) の中間状態はサポートされていません。たとえば サーバー側で sumMerge(column) を使って最終化し、その結果を読み取ってください。
  • 2引数でストライドを指定しない QBit(T, N) レイアウトのみがサポートされています。
  • JSON には ClickHouse の String シリアライゼーションが使用されるため、 output_format_native_write_json_as_string = 1 が必要です。クライアントはデフォルトでこの設定を要求します。
  • アプリケーション側で作成した挿入データには、flatten_nested = 0 の場合、 Nested(...) に対応する行指向の構造がありません。代わりに、デフォルトのフラット化されたドット区切りの Array(T) カラムを使用してください。
  • アプリケーション側で作成した Geometry カラムでは、Ring と LineString のように CLR 上で同じ 構造を持つ型を区別して推論できません。具体的なジオメトリ型の値を挿入するか、判別子を保持しているデコード済みの Geometry カラムを再挿入してください。

自動再試行

クライアントは失敗した操作を自動的には再試行しません。安全に繰り返せる操作だけを 再試行してください。また、挿入の成否が不明な場合は、再試行する前に一定の値のDeduplicationTokenを設定してください。 詳しくは操作の再試行を参照してください。
最終更新日 2026年10月14日