ClickHouse C# 客户端
用于连接 ClickHouse 的官方 C# 客户端。客户端源代码可在 GitHub 仓库 中找到。最初由 Oleg V. Kozlyuk 开发。
迁移指南
- 使用新的包名称
ClickHouse.Driver和 NuGet 上的最新版本 更新你的.csproj文件。 - 在你的代码库中,将所有
ClickHouse.Client引用更新为ClickHouse.Driver。
支持的 .NET 版本
ClickHouse.Driver 支持以下 .NET 版本
- .NET Framework 4.6.2
- .NET Framework 4.8
- .NET Standard 2.1
- .NET 6.0
- .NET 8.0
- .NET 9.0
- .NET 10.0
安装
从 NuGet 安装包
或者使用 NuGet 包管理器
快速入门
配置
有两种方式配置你与 ClickHouse 的连接
- 连接字符串: 分号分隔的键/值对,用于指定主机、身份验证凭据和其他连接选项。
ClickHouseClientSettings对象: 一个强类型配置对象,可以从配置文件加载或在代码中设置。
以下是所有设置、默认值及其影响的完整列表。
连接设置
| 属性 | 类型 | 默认值 | 连接字符串键 | 描述 |
|---|---|---|---|---|
| Host | string | "localhost" | Host | ClickHouse 服务器的主机名或 IP 地址 |
| 端口 | ushort | 8123 (HTTP) / 8443 (HTTPS) | 端口 | 端口号;默认值基于协议 |
| 用户名 | string | "default" | 用户名 | 身份验证用户名 |
| 密码 | string | "" | 密码 | 身份验证密码 |
| 数据库 | string | "" | 数据库 | 默认数据库;空值使用服务器/用户默认值 |
| 协议 | string | "http" | 协议 | 连接协议:"http" 或 "https" |
| 路径 | string | null | 路径 | 反向代理场景的 URL 路径(例如,/clickhouse) |
| 超时 | TimeSpan | 2 分钟 | 超时 | 操作超时(在连接字符串中存储为秒) |
数据格式 & 序列化
| 属性 | 类型 | 默认值 | 连接字符串键 | 描述 |
|---|---|---|---|---|
| UseCompression | bool | true | 压缩 | 启用 gzip 压缩进行数据传输 |
| UseCustomDecimals | bool | true | UseCustomDecimals | 使用 ClickHouseDecimal 进行任意精度;如果为 false,则使用 .NET decimal(128 位限制) |
| UseFormDataParameters | bool | false | UseFormDataParameters | 将参数作为表单数据而不是 URL 查询字符串发送 |
会话管理
| 属性 | 类型 | 默认值 | 连接字符串键 | 描述 |
|---|---|---|---|---|
| UseSession | bool | false | UseSession | 启用有状态会话;序列化请求 |
| SessionId | string | null | SessionId | 会话 ID;如果 UseSession 为 true 且为 null,则自动生成 GUID |
UseSession 标志启用服务器会话的持久性,允许使用 SET 语句和临时表。会话将在 60 秒不活动后重置(默认超时)。可以通过 ClickHouse 语句或服务器配置来延长会话生命周期。
启用 UseSession 标志会将活动查询限制为每个连接的单个查询(这是服务器端限制)。
安全性
| 属性 | 类型 | 默认值 | 连接字符串键 | 描述 |
|---|---|---|---|---|
| SkipServerCertificateValidation | bool | false | — | 跳过 HTTPS 证书验证;不用于生产环境 |
HTTP 客户端配置
| 属性 | 类型 | 默认值 | 连接字符串键 | 描述 |
|---|---|---|---|---|
| HttpClient | HttpClient | null | — | 自定义预配置的 HttpClient 实例 |
| HttpClientFactory | IHttpClientFactory | null | — | 用于创建 HttpClient 实例的自定义工厂 |
| HttpClientName | string | null | — | 用于 HttpClientFactory 创建特定客户端的名称 |
日志记录 & 调试
| 属性 | 类型 | 默认值 | 连接字符串键 | 描述 |
|---|---|---|---|---|
| LoggerFactory | ILoggerFactory | null | — | 用于诊断日志记录的记录器工厂 |
| EnableDebugMode | bool | false | — | 启用 .NET 网络跟踪(需要 LoggerFactory 将级别设置为 Trace);显著影响性能 |
自定义设置 & 角色
| 属性 | 类型 | 默认值 | 连接字符串键 | 描述 |
|---|---|---|---|---|
| CustomSettings | IDictionary<string, object> | 空 | set_* 前缀 | ClickHouse 服务器设置,请参阅下面的说明。 |
| Roles | IReadOnlyList<string> | 空 | Roles | 逗号分隔的 ClickHouse 角色(例如,Roles=admin,reader) |
在使用连接字符串设置自定义设置时,请使用 set_ 前缀,例如 "set_max_threads=4"。在使用 ClickHouseClientSettings 对象时,请不要使用 set_ 前缀。
有关可用设置的完整列表,请参阅 此处。
连接字符串示例
基本连接
使用自定义 ClickHouse 设置
用法
连接
要连接到 ClickHouse,请使用连接字符串或 ClickHouseClientSettings 对象创建一个 ClickHouseConnection。有关可用选项,请参阅 配置 部分。
你的 ClickHouse Cloud 服务的详细信息可在 ClickHouse Cloud 控制台中找到。
选择一个服务并单击 Connect
选择 C#。将显示连接详细信息。
如果您使用的是自托管 ClickHouse,则连接详细信息由您的 ClickHouse 管理员设置。
使用连接字符串
或者使用 ClickHouseClientSettings
- 一个
ClickHouseConnection代表与服务器的“会话”。它通过查询服务器版本执行功能发现(因此打开时存在轻微的开销),但通常可以多次创建和销毁此类对象。 - 连接的推荐生命周期是每个大型“事务”跨多个查询的一个连接对象。
ClickHouseConnection对象可以长期存在。底层 TCP 连接将由连接池回收。 - 如果应用程序处理大量事务并需要频繁创建/销毁
ClickHouseConnection对象,建议使用IHttpClientFactory或静态HttpClient实例来管理连接。
创建表
使用标准 SQL 语法创建一个表
插入数据
使用参数化查询插入数据
批量插入
使用 ClickHouseBulkCopy 插入大量行。它使用 ClickHouse 的本机行二进制格式有效地流式传输数据,并行工作并将数据分成批处理。它还避免了由于参数集过大而导致的“URL 过长”错误。
使用 ClickHouseBulkCopy 需要
- 目标连接(
ClickHouseConnection实例) - 目标表名(
DestinationTableName属性) - 数据源(
IDataReader或IEnumerable<object[]>)
- 为了获得最佳性能,ClickHouseBulkCopy 使用任务并行库 (TPL) 处理数据批处理,最多有 4 个并行插入任务(可以进行调整)。
- 如果源数据比目标表中的列少,可以通过
ColumnNames属性可选地提供列名。 - 可配置参数:
Columns、BatchSize、MaxDegreeOfParallelism。 - 在复制之前,将执行
SELECT * FROM <table> LIMIT 0查询以获取目标表结构的详细信息。提供的对象的类型必须与目标表合理匹配。 - 会话与并行插入不兼容。传递给
ClickHouseBulkCopy的连接必须禁用会话,或者MaxDegreeOfParallelism必须设置为1。
执行 SELECT 查询
使用 ExecuteReader() 或 ExecuteReaderAsync() 执行 SELECT 查询。返回的 DbDataReader 通过 GetInt64()、GetString() 和 GetFieldValue<T>() 等方法提供对结果列的类型化访问。
调用 Read() 以前进到下一行。当没有更多行时,它返回 false。按索引(从 0 开始)或按列名访问列。
SQL 参数
在 ClickHouse 中,SQL 查询中参数的标准格式为 {parameter_name:DataType}。
示例
SQL “绑定”参数作为 HTTP URI 查询参数传递,因此使用过多的参数可能会导致“URL 过长”异常。使用 ClickHouseBulkInsert 可以绕过此限制。
查询 ID
执行每个查询的方法也会在结果中包含一个 query_id。此唯一标识符由客户端为每个查询分配,可用于从 system.query_log 表(如果已启用)中获取数据,或取消长时间运行的查询。如果需要,可以在 ClickHouseCommand 对象中覆盖查询 ID。
如果您正在覆盖 QueryId 参数,则需要确保每次调用它的唯一性。随机 GUID 是一个不错的选择。
原始流式传输
可以绕过数据读取器直接流式传输特定格式的数据。这在希望以特定格式将数据保存到文件中的情况下很有用。例如
原始流式插入
使用 InsertRawStreamAsync 直接从文件或内存流中以 CSV、JSON 或任何 支持的 ClickHouse 格式 插入数据。
从 CSV 文件插入
有关控制数据导入行为的选项,请参阅 格式设置文档。
更多示例
有关其他实际用法示例,请参阅 GitHub 仓库中的 examples 目录。
最佳实践
连接生命周期和连接池
ClickHouse.Driver 在底层使用 System.Net.Http.HttpClient。HttpClient 具有每个端点的连接池。因此
ClickHouseConnection对象与 TCP 连接没有 1:1 映射 - 多个数据库会话将通过每个服务器的几个 TCP 连接多路复用。ClickHouseConnection对象可以长期存在;底层的 TCP 连接将由连接池回收。- 让
HttpClient内部管理连接池。不要自己池化ClickHouseConnection对象。 - 在
ClickHouseConnection对象已释放后,连接可以保持活动状态。 - 可以通过传递自定义
HttpClientFactory或具有自定义HttpClientHandler的HttpClient来调整此行为。
对于 DI 环境,有一个定制的构造函数 ClickHouseConnection(string connectionString, IHttpClientFactory httpClientFactory, string httpClientName = ""),它使 ClickHouseConnection 请求一个命名的 http 客户端。
在使用自定义 HttpClient 或 HttpClientFactory 时,请确保将 PooledConnectionIdleTimeout 设置为小于服务器 keep_alive_timeout 的值,以避免由于半关闭连接而导致的错误。Cloud 部署的默认 keep_alive_timeout 为 10 秒。
DateTime 处理
-
尽可能使用 UTC。 将时间戳存储为
DateTime('UTC')列,并在代码中使用DateTimeKind.Utc。 这消除了时区歧义。 -
对于显式时区处理,请使用
DateTimeOffset。 它始终表示一个特定的时刻,并包含偏移信息。 -
在 HTTP 参数类型提示中指定时区。 当使用针对非 UTC 列的
UnspecifiedDateTime 值的参数时
异步插入
异步插入 将批处理的责任从客户端转移到服务器。 不再需要客户端批处理,服务器会缓冲传入的数据,并根据可配置的阈值将其刷新到存储中。 这对于高并发场景(例如可观察性工作负载,其中许多代理发送小负载)非常有用。
通过 CustomSettings 或连接字符串启用异步插入
两种模式(由 wait_for_async_insert 控制)
| 模式 | 行为 | 用例 |
|---|---|---|
wait_for_async_insert=1 | 插入在数据刷新到磁盘后返回。 错误会返回给客户端。 | 推荐 用于大多数工作负载 |
wait_for_async_insert=0 | 插入在数据缓冲后立即返回。 不保证数据会被持久化。 | 仅当数据丢失是可以接受时 |
使用 wait_for_async_insert=0 时,错误仅在刷新期间出现,并且无法追溯到原始插入。 客户端也无法提供反压,从而可能导致服务器过载。
关键设置
| 设置 | 描述 |
|---|---|
async_insert_max_data_size | 当缓冲区达到此大小时(字节)刷新 |
async_insert_busy_timeout_ms | 在此超时后刷新(毫秒) |
async_insert_max_query_number | 累积到这么多查询后刷新 |
会话
仅在需要有状态服务器端功能时才启用会话,例如:
- 临时表 (
CREATE TEMPORARY TABLE) - 在多个语句之间维护查询上下文
- 会话级别设置 (
SET max_threads = 4)
启用会话后,请求将被序列化以防止并发使用相同的会话。 这会为不需要会话状态的工作负载增加开销。
支持的数据类型
ClickHouse.Driver 支持所有 ClickHouse 数据类型。 下面的表格显示了读取数据库数据时 ClickHouse 类型与本机 .NET 类型之间的映射。
类型映射:从 ClickHouse 读取
整数类型
| ClickHouse 类型 | .NET 类型 |
|---|---|
| Int8 | sbyte |
| UInt8 | byte |
| Int16 | short |
| UInt16 | ushort |
| Int32 | int |
| UInt32 | uint |
| Int64 | long |
| UInt64 | ulong |
| Int128 | BigInteger |
| UInt128 | BigInteger |
| Int256 | BigInteger |
| UInt256 | BigInteger |
浮点类型
| ClickHouse 类型 | .NET 类型 |
|---|---|
| Float32 | float |
| Float64 | double |
| BFloat16 | float |
十进制类型
| ClickHouse 类型 | .NET 类型 |
|---|---|
| Decimal(P, S) | decimal / ClickHouseDecimal |
| Decimal32(S) | decimal / ClickHouseDecimal |
| Decimal64(S) | decimal / ClickHouseDecimal |
| Decimal128(S) | decimal / ClickHouseDecimal |
| Decimal256(S) | decimal / ClickHouseDecimal |
十进制类型转换由 UseCustomDecimals 设置控制。
布尔类型
| ClickHouse 类型 | .NET 类型 |
|---|---|
| Bool | bool |
字符串类型
| ClickHouse 类型 | .NET 类型 |
|---|---|
| String | string |
| FixedString(N) | byte[] |
日期和时间类型
| ClickHouse 类型 | .NET 类型 |
|---|---|
| Date | DateTime |
| Date32 | DateTime |
| DateTime | DateTime |
| DateTime32 | DateTime |
| DateTime64 | DateTime |
| Time | TimeSpan |
| Time64 | TimeSpan |
ClickHouse 内部将 DateTime 和 DateTime64 值存储为 Unix 时间戳(自纪元以来的秒或亚秒单位)。 虽然存储始终以 UTC 为单位,但列可以关联一个时区,该时区会影响值的显示和解释方式。
读取 DateTime 值时,DateTime.Kind 属性基于列的时区设置
| 列定义 | 返回的 DateTime.Kind | 注意事项 |
|---|---|---|
DateTime('UTC') | Utc | 显式 UTC 时区 |
DateTime('Europe/Amsterdam') | Unspecified | 偏移已应用 |
DateTime | Unspecified | 保留壁钟时间 |
对于非 UTC 列,返回的 DateTime 表示该时区中的壁钟时间。 使用 ClickHouseDataReader.GetDateTimeOffset() 获取具有该时区正确偏移的 DateTimeOffset
对于没有显式时区(即,DateTime 而不是 DateTime('Europe/Amsterdam'))的列,驱动程序返回一个 DateTime,其 Kind=Unspecified。 这会精确地保留存储的壁钟时间,而不会对时区做出任何假设。
如果您需要对没有显式时区的列进行时区感知行为,请执行以下操作:
- 在列定义中使用显式时区:
DateTime('UTC')或DateTime('Europe/Amsterdam') - 在读取后自行应用时区。
其他类型
| ClickHouse 类型 | .NET 类型 |
|---|---|
| UUID | Guid |
| IPv4 | IPAddress |
| IPv6 | IPAddress |
| Nothing | DBNull |
| Dynamic | 请参阅注释 |
| Json | JsonObject |
| Array(T) | T[] |
| Tuple(T1, T2, ...) | Tuple<T1, T2, ...> / LargeTuple |
| Map(K, V) | Dictionary<K, V> |
| Nullable(T) | T? |
| Enum8 | string |
| Enum16 | string |
| LowCardinality(T) | 与 T 相同 |
| SimpleAggregateFunction | 与底层类型相同 |
| Nested(...) | Tuple[] |
| Variant(T1, T2, ...) | 请参阅注释 |
| QBit(T, dimension) | T[] |
Dynamic 和 Variant 类型将转换为每行实际底层类型的相应类型。
几何类型
| ClickHouse 类型 | .NET 类型 |
|---|---|
| Point | Tuple<double, double> |
| Ring | Tuple<double, double>[] |
| LineString | Tuple<double, double>[] |
| Polygon | Ring[] |
| MultiLineString | LineString[] |
| MultiPolygon | Polygon[] |
| Geometry | 请参阅注释 |
Geometry 类型是一种 Variant 类型,可以容纳任何几何类型。 它将被转换为相应的类型。
类型映射:写入 ClickHouse
在插入数据时,驱动程序将 .NET 类型转换为相应的 ClickHouse 类型。 下面的表格显示了每个 ClickHouse 列类型接受的 .NET 类型。
整数类型
| ClickHouse 类型 | 接受的 .NET 类型 | 注意事项 |
|---|---|---|
| Int8 | sbyte,任何 Convert.ToSByte() 兼容的类型 | |
| UInt8 | byte,任何 Convert.ToByte() 兼容的类型 | |
| Int16 | short,任何 Convert.ToInt16() 兼容的类型 | |
| UInt16 | ushort,任何 Convert.ToUInt16() 兼容的类型 | |
| Int32 | int,任何 Convert.ToInt32() 兼容的类型 | |
| UInt32 | uint,任何 Convert.ToUInt32() 兼容的类型 | |
| Int64 | long,任何 Convert.ToInt64() 兼容的类型 | |
| UInt64 | ulong,任何 Convert.ToUInt64() 兼容的类型 | |
| Int128 | BigInteger, decimal, double, float, int, uint, long, ulong,任何 Convert.ToInt64() 兼容的类型 | |
| UInt128 | BigInteger, decimal, double, float, int, uint, long, ulong,任何 Convert.ToInt64() 兼容的类型 | |
| Int256 | BigInteger, decimal, double, float, int, uint, long, ulong,任何 Convert.ToInt64() 兼容的类型 | |
| UInt256 | BigInteger, decimal, double, float, int, uint, long, ulong,任何 Convert.ToInt64() 兼容的类型 |
浮点类型
| ClickHouse 类型 | 接受的 .NET 类型 | 注意事项 |
|---|---|---|
| Float32 | float,任何 Convert.ToSingle() 兼容的类型 | |
| Float64 | double,任何 Convert.ToDouble() 兼容的类型 | |
| BFloat16 | float,任何 Convert.ToSingle() 兼容的类型 | 截断为 16 位脑浮点格式 |
布尔类型
| ClickHouse 类型 | 接受的 .NET 类型 | 注意事项 |
|---|---|---|
| Bool | bool |
字符串类型
| ClickHouse 类型 | 接受的 .NET 类型 | 注意事项 |
|---|---|---|
| String | string,任何 Convert.ToString() 兼容的类型 | |
| FixedString(N) | string, byte[] | 字符串采用 UTF-8 编码并填充/截断;byte[] 必须正好是 N 个字节 |
日期和时间类型
| ClickHouse 类型 | 接受的 .NET 类型 | 注意事项 |
|---|---|---|
| Date | DateTime, DateTimeOffset, DateOnly, NodaTime 类型 | 转换为 Unix 天数作为 UInt16 |
| Date32 | DateTime, DateTimeOffset, DateOnly, NodaTime 类型 | 转换为 Unix 天数作为 Int32 |
| DateTime | DateTime, DateTimeOffset, DateOnly, NodaTime 类型 | 有关详细信息,请参阅下文 |
| DateTime32 | DateTime, DateTimeOffset, DateOnly, NodaTime 类型 | 与 DateTime 相同 |
| DateTime64 | DateTime, DateTimeOffset, DateOnly, NodaTime 类型 | 基于 Scale 参数的精度 |
| Time | TimeSpan, int | 限制为 ±999:59:59;int 被视为秒 |
| Time64 | TimeSpan, decimal, double, float, int, long, string | 字符串解析为 [-]HHH:MM:SS[.fraction];限制为 ±999:59:59.999999999 |
驱动程序在写入值时会尊重 DateTime.Kind
DateTime.Kind | 行为 |
|---|---|
Utc | 精确保留瞬间 |
本地 | 使用系统时区转换为 UTC,保留瞬间 |
Unspecified | 按目标列的时区处理壁钟时间 |
DateTimeOffset 值始终保留精确的瞬间。
示例:UTC DateTime(瞬间保留)
示例:未指定的 DateTime(壁钟时间)
建议: 为了获得最简单和最可预测的行为,请对所有 DateTime 操作使用 DateTimeKind.Utc 或 DateTimeOffset。 这可确保您的代码无论服务器时区、客户端时区或列时区如何都能始终如一地工作。
HTTP 参数与批量复制
在写入 Unspecified DateTime 值时,HTTP 参数绑定和批量复制之间存在重要差异
批量复制 知道目标列的时区,并正确解释该时区中的 Unspecified 值。
HTTP 参数 无法自动知道列的时区。 您必须在参数类型提示中指定它
DateTime.Kind | 目标列 | HTTP 参数(带有 tz 提示) | HTTP 参数(没有 tz 提示) | 批量复制 |
|---|---|---|---|---|
Utc | UTC | 保留瞬间 | 保留瞬间 | 保留瞬间 |
Utc | Europe/Amsterdam | 保留瞬间 | 保留瞬间 | 保留瞬间 |
本地 | 任何 | 保留瞬间 | 保留瞬间 | 保留瞬间 |
Unspecified | UTC | 视为 UTC | 视为 UTC | 视为 UTC |
Unspecified | Europe/Amsterdam | 视为阿姆斯特丹时间 | 视为 UTC | 视为阿姆斯特丹时间 |
十进制类型
| ClickHouse 类型 | 接受的 .NET 类型 | 注意事项 |
|---|---|---|
| Decimal(P,S) | decimal, ClickHouseDecimal,任何 Convert.ToDecimal() 兼容的类型 | 如果超出精度,则抛出 OverflowException |
| Decimal32 | decimal, ClickHouseDecimal,任何 Convert.ToDecimal() 兼容的类型 | 最大精度 9 |
| Decimal64 | decimal, ClickHouseDecimal,任何 Convert.ToDecimal() 兼容的类型 | 最大精度 18 |
| Decimal128 | decimal, ClickHouseDecimal,任何 Convert.ToDecimal() 兼容的类型 | 最大精度 38 |
| Decimal256 | decimal, ClickHouseDecimal,任何 Convert.ToDecimal() 兼容的类型 | 最大精度 76 |
其他类型
| ClickHouse 类型 | 接受的 .NET 类型 | 注意事项 |
|---|---|---|
| UUID | Guid, string | 将字符串解析为 Guid |
| IPv4 | IPAddress, string | 必须是 IPv4;字符串通过 IPAddress.Parse() 解析 |
| IPv6 | IPAddress, string | 必须是 IPv6;字符串通过 IPAddress.Parse() 解析 |
| Nothing | 任何 | 不执行任何操作(无操作) |
| Dynamic | — | 不支持(抛出 NotImplementedException) |
| Json | string, JsonObject, 任何对象 | 将字符串解析为 JSON;对象通过 JsonSerializer 序列化 |
| Array(T) | IList, null | Null 写入空数组 |
| Tuple(T1, T2, ...) | ITuple, IList | 元素计数必须与元组基数匹配 |
| Map(K, V) | IDictionary | |
| Nullable(T) | null、DBNull 或 T 接受的类型 | 在值之前写入 null 标志字节 |
| Enum8 | string、sbyte、数值类型 | 在枚举字典中查找的字符串 |
| Enum16 | string、short、数值类型 | 在枚举字典中查找的字符串 |
| LowCardinality(T) | T 接受的类型 | 委托给底层类型 |
| SimpleAggregateFunction | 底层类型接受的类型 | 委托给底层类型 |
| Nested(...) | IList 的元组 | 元素计数必须与字段计数匹配 |
| Variant(T1, T2, ...) | 与 T1、T2、... 中的一个值匹配 | 如果没有类型匹配则抛出 ArgumentException |
| QBit(T, dim) | IList | 委托给 Array;维度仅为元数据 |
几何类型
| ClickHouse 类型 | 接受的 .NET 类型 | 注意事项 |
|---|---|---|
| Point | System.Drawing.Point、ITuple、IList(2 个元素) | |
| Ring | IList 的点 | |
| LineString | IList 的点 | |
| Polygon | IList 的环 | |
| MultiLineString | IList 的 LineStrings | |
| MultiPolygon | IList 的多边形 | |
| Geometry | 以上任何几何类型 | 所有几何类型的变体 |
不支持写入
| ClickHouse 类型 | 注意事项 |
|---|---|
| Dynamic | 抛出 NotImplementedException |
| AggregateFunction | 抛出 AggregateFunctionException |
嵌套类型处理
ClickHouse 嵌套类型(Nested(...))可以使用数组语义进行读取和写入。
日志记录和诊断
ClickHouse .NET 客户端与 Microsoft.Extensions.Logging 抽象集成,以提供轻量级、选择加入的日志记录。启用后,驱动程序会为连接生命周期事件、命令执行、传输操作和批量复制上传发出结构化消息。日志记录完全是可选的——不配置记录器的应用程序将继续运行而不会产生额外的开销。
快速入门
使用 ClickHouseConnection
使用 appsettings.json
您可以使用标准的 .NET 配置来配置日志级别
使用内存配置
您还可以通过代码按类别配置日志详细程度
类别和发射器
驱动程序使用专用类别,以便您可以微调每个组件的日志级别
| 类别 | 来源 | 亮点 |
|---|---|---|
ClickHouse.Driver.Connection | ClickHouseConnection | 连接生命周期、HTTP 客户端工厂选择、连接打开/关闭、会话管理。 |
ClickHouse.Driver.Command | ClickHouseCommand | 查询执行开始/完成、计时、查询 ID、服务器统计信息和错误详细信息。 |
ClickHouse.Driver.Transport | ClickHouseConnection | 低级 HTTP 流式请求、压缩标志、响应状态代码和传输故障。 |
ClickHouse.Driver.BulkCopy | ClickHouseBulkCopy | 元数据加载、批量操作、行计数和上传完成。 |
ClickHouse.Driver.NetTrace | TraceHelper | 网络跟踪,仅在调试模式下启用 |
示例:诊断连接问题
这将记录
- HTTP 客户端工厂选择(默认池与单个连接)
- HTTP 处理程序配置(SocketsHttpHandler 或 HttpClientHandler)
- 连接池设置(MaxConnectionsPerServer、PooledConnectionLifetime 等)
- 超时设置(ConnectTimeout、Expect100ContinueTimeout 等)
- SSL/TLS 配置
- 连接打开/关闭事件
- 会话 ID 跟踪
调试模式:网络跟踪和诊断
为了帮助诊断网络问题,驱动程序库包含一个助手,可以启用 .NET 网络内部的低级跟踪。要启用它,您必须传递一个 LoggerFactory,其级别设置为 Trace,并将 EnableDebugMode 设置为 true(或通过 ClickHouse.Driver.Diagnostic.TraceHelper 类手动启用它)。事件将记录到 ClickHouse.Driver.NetTrace 类别。警告:这将生成极其详细的日志,并影响性能。不建议在生产环境中启用调试模式。
OpenTelemetry
驱动程序通过 .NET System.Diagnostics.Activity API 提供对 OpenTelemetry 分布式跟踪的内置支持。启用后,驱动程序会为可以导出到可观察性后端(如 Jaeger 或 ClickHouse 本身(通过 OpenTelemetry Collector))的数据库操作发出跨度。
启用跟踪
在 ASP.NET Core 应用程序中,将 ClickHouse 驱动程序的 ActivitySource 添加到您的 OpenTelemetry 配置
对于控制台应用程序、测试或手动设置
跨度属性
每个跨度都包含标准的 OpenTelemetry 数据库属性以及 ClickHouse 特定的查询统计信息,可用于调试。
| 属性 | 描述 |
|---|---|
db.system | 始终为 "clickhouse" |
db.name | 数据库名称 |
db.user | 用户名 |
db.statement | SQL 查询(如果启用) |
db.clickhouse.read_rows | 查询读取的行数 |
db.clickhouse.read_bytes | 查询读取的字节数 |
db.clickhouse.written_rows | 查询写入的行数 |
db.clickhouse.written_bytes | 查询写入的字节数 |
db.clickhouse.elapsed_ns | 服务器端执行时间,以纳秒为单位 |
配置选项
通过 ClickHouseDiagnosticsOptions 控制跟踪行为
启用 IncludeSqlInActivityTags 可能会在您的跟踪中暴露敏感数据。在生产环境中使用时请谨慎。
TLS 配置
通过 HTTPS 连接到 ClickHouse 时,您可以以多种方式配置 TLS/SSL 行为。
自定义证书验证
对于需要自定义证书验证逻辑的生产环境,请提供配置了 ServerCertificateCustomValidationCallback 处理程序的自定义 HttpClient
提供自定义 HttpClient 时的重要注意事项
- 自动解压缩:如果未禁用压缩(默认情况下启用压缩),则必须启用
AutomaticDecompression。 - 空闲超时:将
PooledConnectionIdleTimeout设置为小于服务器的keep_alive_timeout(ClickHouse Cloud 为 10 秒)以避免来自半打开连接的连接错误。
ORM 支持
Dapper
ClickHouse.Driver 可以与 Dapper 一起使用,但不支持匿名对象。
工作示例
不支持
Linq2db
此驱动程序与 linq2db 兼容,linq2db 是 .NET 的轻量级 ORM 和 LINQ 提供程序。有关详细文档,请参阅项目网站。
示例用法
使用 ClickHouse 提供程序创建一个 DataConnection
可以使用属性或流式配置定义表映射。如果您的类和属性名称与表和列名称完全匹配,则不需要配置
查询
批量复制
使用 BulkCopyAsync 进行高效的批量插入。
Entity framework core
目前不支持 Entity Framework Core。
限制
AggregateFunction 列
类型为 AggregateFunction(...) 的列不能直接查询或插入。
要插入
要选择