ClickHouse Connect 与 Python 集成
简介
ClickHouse Connect 是一个核心数据库驱动程序,提供与各种 Python 应用程序的互操作性。
- 主要接口是
clickhouse_connect.driver
包中的Client
对象。该核心包还包括用于与 ClickHouse 服务器通信的各种辅助类和实用程序函数,以及用于高级管理插入和选择查询的“上下文”实现。 clickhouse_connect.datatypes
包为所有非实验性 ClickHouse 数据类型提供基本实现和子类。其主要功能是将 ClickHouse 数据序列化和反序列化为 ClickHouse “原生”二进制列式格式,用于实现 ClickHouse 和客户端应用程序之间最高效的传输。clickhouse_connect.cdriver
包中的 Cython/C 类优化了一些最常见的序列化和反序列化操作,从而显著提高了与纯 Python 相比的性能。clickhouse_connect.cc_sqlalchemy
包中有一个有限的 SQLAlchemy 方言,它基于datatypes
和dbi
包构建。此受限实现侧重于查询/游标功能,通常不支持 SQLAlchemy DDL 和 ORM 操作。(SQLAlchemy 面向 OLTP 数据库,我们建议使用更专业的工具和框架来管理面向 ClickHouse OLAP 的数据库。)- 核心驱动程序和 ClickHouse Connect SQLAlchemy 实现是将 ClickHouse 连接到 Apache Superset 的首选方法。使用
ClickHouse Connect
数据库连接或clickhousedb
SQLAlchemy 方言连接字符串。
此文档截至 beta 版本 0.8.2。
官方 ClickHouse Connect Python 驱动程序使用 HTTP 协议与 ClickHouse 服务器通信。它具有一些优势(例如更好的灵活性和 HTTP 负载均衡器支持,以及与基于 JDBC 的工具的更好兼容性等)和缺点(例如压缩和性能略低,以及缺乏对某些基于原生 TCP 协议的复杂功能的支持)。对于某些用例,您可以考虑使用使用基于原生 TCP 协议的 社区 Python 驱动程序 之一。
要求和兼容性
Python | 平台¹ | ClickHouse | SQLAlchemy² | Apache Superset | |||||
---|---|---|---|---|---|---|---|---|---|
2.x, <3.8 | ❌ | Linux (x86) | ✅ | <24.3³ | 🟡 | <1.3 | ❌ | <1.4 | ❌ |
3.8.x | ✅ | Linux (Aarch64) | ✅ | 24.3.x | ✅ | 1.3.x | ✅ | 1.4.x | ✅ |
3.9.x | ✅ | macOS (x86) | ✅ | 24.4-24.6³ | 🟡 | 1.4.x | ✅ | 1.5.x | ✅ |
3.10.x | ✅ | macOS (ARM) | ✅ | 24.7.x | ✅ | >=2.x | ❌ | 2.0.x | ✅ |
3.11.x | ✅ | Windows | ✅ | 24.8.x | ✅ | 2.1.x | ✅ | ||
3.12.x | ✅ | 24.9.x | ✅ | 3.0.x | ✅ |
¹ClickHouse Connect 已针对列出的平台进行了明确测试。此外,还为出色的 cibuildwheel 项目支持的所有架构构建了未经测试的二进制轮子(使用 C 优化)。最后,由于 ClickHouse Connect 也可以作为纯 Python 运行,因此源代码安装应该可以在任何最近的 Python 安装上工作。
²同样,SQLAlchemy 支持主要限于查询功能。不支持完整的 SQLAlchemy API。
³ClickHouse Connect 已针对所有当前支持的 ClickHouse 版本进行了测试。因为它使用 HTTP 协议,所以它也应该适用于大多数其他 ClickHouse 版本,尽管某些高级数据类型可能存在一些不兼容性。
安装
通过 pip 从 PyPI 安装 ClickHouse Connect
pip install clickhouse-connect
ClickHouse Connect 也可以从源代码安装
git clone
GitHub 仓库。- (可选) 运行
pip install cython
以构建并启用 C/Cython 优化 cd
到项目根目录并运行pip install .
支持策略
ClickHouse Connect 目前处于 beta 阶段,并且仅积极支持当前的 beta 版本。在报告任何问题之前,请更新到最新版本。问题应在 GitHub 项目 中提出。ClickHouse Connect 的未来版本保证与发布时积极支持的 ClickHouse 版本兼容(通常是最近三个 stable
版本和最近两个 lts
版本)。
基本用法
收集您的连接详细信息
要使用 HTTP(S) 连接到 ClickHouse,您需要以下信息
主机和端口:通常,使用 TLS 时端口为 8443,不使用 TLS 时端口为 8123。
数据库名称:默认情况下,有一个名为
default
的数据库,请使用您要连接到的数据库的名称。用户名和密码:默认情况下,用户名为
default
。使用适合您用例的用户名。
您的 ClickHouse Cloud 服务的详细信息可在 ClickHouse Cloud 控制台中找到。选择您要连接的服务,然后点击连接
选择HTTPS,详细信息可在示例 curl
命令中找到。
如果您使用的是自托管 ClickHouse,则连接详细信息由您的 ClickHouse 管理员设置。
建立连接
下面显示了两个连接到 ClickHouse 的示例
- 连接到本地主机上的 ClickHouse 服务器。
- 连接到 ClickHouse Cloud 服务。
使用 ClickHouse Connect 客户端实例连接到本地主机上的 ClickHouse 服务器:
import clickhouse_connect
client = clickhouse_connect.get_client(host='localhost', username='default', password='password')
使用 ClickHouse Connect 客户端实例连接到 ClickHouse Cloud 服务:
使用之前收集的连接详细信息。ClickHouse Cloud 服务需要 TLS,因此请使用端口 8443。
import clickhouse_connect
client = clickhouse_connect.get_client(host='HOSTNAME.clickhouse.cloud', port=8443, username='default', password='your password')
与您的数据库交互
要运行 ClickHouse SQL 命令,请使用客户端的 command
方法
client.command('CREATE TABLE new_table (key UInt32, value String, metric Float64) ENGINE MergeTree ORDER BY key')
要插入批处理数据,请使用客户端的 insert
方法,并使用一个二维数组表示行和值
row1 = [1000, 'String Value 1000', 5.233]
row2 = [2000, 'String Value 2000', -107.04]
data = [row1, row2]
client.insert('new_table', data, column_names=['key', 'value', 'metric'])
要使用 ClickHouse SQL 检索数据,请使用客户端的 query
方法
result = client.query('SELECT max(key), avg(metric) FROM new_table')
result.result_rows
Out[13]: [(2000, -50.9035)]
ClickHouse Connect 驱动程序 API
注意:鉴于可能存在大量参数(其中大多数是可选的),建议对大多数 api 方法使用关键字参数。
此处未记录的方法不被视为 API 的一部分,可能会被删除或更改。
客户端初始化
clickhouse_connect.driver.client
类提供了 Python 应用程序与 ClickHouse 数据库服务器之间的主要接口。使用 clickhouse_connect.get_client
函数获取 Client 实例,该函数接受以下参数
连接参数
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
interface | str | http | 必须是 http 或 https。 |
host | str | localhost | ClickHouse 服务器的主机名或 IP 地址。如果未设置,将使用 localhost 。 |
port | int | 8123 或 8443 | ClickHouse HTTP 或 HTTPS 端口。如果未设置,将默认为 8123,或者如果 secure=True 或 interface=https,则默认为 8443。 |
username | str | default | ClickHouse 用户名。如果未设置,将使用 default ClickHouse 用户。 |
password | str | <空字符串> | username 的密码。 |
数据库 | str | 无 | 连接的默认数据库。如果未设置,ClickHouse Connect 将使用用户名的默认数据库。 |
安全 | 布尔值 | False | 使用 https/TLS。这将覆盖从接口或端口参数推断出的值。 |
数据源名称 (DSN) | str | 无 | 标准 DSN(数据源名称)格式的字符串。如果未另行设置,其他连接值(如主机或用户)将从此字符串中提取。 |
压缩 | 布尔值或字符串 | True | 启用 ClickHouse HTTP 插入和查询结果的压缩。参见其他选项(压缩) |
查询限制 | int | 0(无限制) | 任何query 响应返回的最大行数。将其设置为零以返回无限行。请注意,如果结果未流式传输,则较大的查询限制可能会导致内存不足异常,因为所有结果都将一次性加载到内存中。 |
查询重试次数 | int | 2 | query 请求的最大重试次数。“可重试”的 HTTP 响应将被重试。驱动程序不会自动重试command 或insert 请求,以防止意外的重复请求。 |
连接超时 | int | 10 | HTTP 连接超时时间(秒)。 |
发送/接收超时 | int | 300 | HTTP 连接的发送/接收超时时间(秒)。 |
客户端名称 | str | 无 | 附加到 HTTP 用户代理标头的客户端名称。将其设置为在 ClickHouse system.query_log 中跟踪客户端查询。 |
连接池管理器 | 对象 | <默认的 PoolManager> | 要使用的urllib3 库 PoolManager。对于需要多个连接池连接到不同主机的复杂用例。 |
HTTP 代理 | str | 无 | HTTP 代理地址(相当于设置 HTTP_PROXY 环境变量)。 |
HTTPS 代理 | str | 无 | HTTPS 代理地址(相当于设置 HTTPS_PROXY 环境变量)。 |
应用服务器时区 | 布尔值 | True | 对于时区感知查询结果,使用服务器时区。参见时区优先级 |
HTTPS/TLS 参数
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
验证 | 布尔值 | True | 如果使用 HTTPS/TLS,则验证 ClickHouse 服务器 TLS/SSL 证书(主机名、过期日期等)。 |
CA 证书 | str | 无 | 如果verify=True,则为验证 ClickHouse 服务器证书的证书颁发机构根的路径(.pem 格式)。如果 verify 为 False,则忽略。如果 ClickHouse 服务器证书是操作系统验证的全局受信任根,则不需要此项。 |
客户端证书 | str | 无 | 客户端 TLS 证书的路径(.pem 格式)(用于双向 TLS 身份验证)。该文件应包含完整的证书链,包括任何中间证书。 |
客户端证书密钥 | str | 无 | 客户端证书的私钥路径。如果私钥未包含在客户端证书密钥文件中,则需要此项。 |
服务器主机名 | str | 无 | 通过其 TLS 证书的 CN 或 SNI 标识的 ClickHouse 服务器主机名。将其设置为避免通过具有不同主机名的代理或隧道连接时出现 SSL 错误。 |
TLS 模式 | str | 无 | 控制高级 TLS 行为。proxy 和 strict 不会调用 ClickHouse 双向 TLS 连接,但会发送客户端证书和密钥。mutual 假设 ClickHouse 双向 TLS 身份验证使用客户端证书。None/默认行为为 mutual 。 |
设置参数
最后,get_client
的settings
参数用于为每个客户端请求将其他 ClickHouse 设置传递到服务器。请注意,在大多数情况下,具有readonly=1访问权限的用户无法更改随查询发送的设置,因此 ClickHouse Connect 将在最终请求中删除此类设置并记录警告。以下设置仅适用于 ClickHouse Connect 使用的 HTTP 查询/会话,并且未作为常规 ClickHouse 设置进行记录。
设置 | 描述 |
---|---|
缓冲区大小 | ClickHouse 服务器在写入 HTTP 通道之前使用的缓冲区大小(以字节为单位)。 |
会话 ID | 用于关联服务器上相关查询的唯一会话 ID。对于临时表是必需的。 |
压缩 | ClickHouse 服务器是否应该压缩 POST 响应数据。此设置仅应用于“原始”查询。 |
解压缩 | 发送到 ClickHouse 服务器的数据是否必须解压缩。此设置仅应用于“原始”插入。 |
配额密钥 | 与此请求关联的配额密钥。请参阅 ClickHouse 服务器文档中的配额。 |
会话检查 | 用于检查会话状态。 |
会话超时 | 会话 ID 标识的会话在不活动多长时间后将超时并且不再被视为有效。默认为 60 秒。 |
等待查询结束 | 缓冲 ClickHouse 服务器上的整个响应。此设置需要返回摘要信息,并且在非流式查询上自动设置。 |
有关可以与每个查询一起发送的其他 ClickHouse 设置,请参阅ClickHouse 文档。
客户端创建示例
- 没有任何参数,ClickHouse Connect 客户端将连接到
localhost
上的默认 HTTP 端口,使用默认用户且没有密码。
import clickhouse_connect
client = clickhouse_connect.get_client()
client.server_version
Out[2]: '22.10.1.98'
- 连接到安全的(https)外部 ClickHouse 服务器。
import clickhouse_connect
client = clickhouse_connect.get_client(host='play.clickhouse.com', secure=True, port=443, user='play', password='clickhouse')
client.command('SELECT timezone()')
Out[2]: 'Etc/UTC'
- 使用会话 ID 和其他自定义连接参数以及 ClickHouse 设置连接。
import clickhouse_connect
client = clickhouse_connect.get_client(host='play.clickhouse.com',
user='play',
password='clickhouse',
port=443,
session_id='example_session_1',
connect_timeout=15,
database='github',
settings={'distributed_ddl_task_timeout':300})
client.database
Out[2]: 'github'
常见方法参数
几个客户端方法使用一个或两个常见的parameters
和settings
参数。这些关键字参数在下面描述。
参数参数
ClickHouse Connect 客户端query*
和command
方法接受一个可选的parameters
关键字参数,用于将 Python 表达式绑定到 ClickHouse 值表达式。可以使用两种绑定。
服务器端绑定
ClickHouse 支持服务器端绑定 用于大多数查询值,其中绑定值作为 HTTP 查询参数与查询分开发送。如果 ClickHouse Connect 检测到以下形式的绑定表达式,它将添加相应的查询参数:{<名称>:<数据类型>}。对于服务器端绑定,parameters
参数应为 Python 字典。
- 使用 Python 字典、DateTime 值和字符串值的服务器端绑定。
import datetime
my_date = datetime.datetime(2022, 10, 1, 15, 20, 5)
parameters = {'table': 'my_table', 'v1': my_date, 'v2': "a string with a single quote'"}
client.query('SELECT * FROM {table:Identifier} WHERE date >= {v1:DateTime} AND string ILIKE {v2:String}', parameters=parameters)
# Generates the following query on the server
# SELECT * FROM my_table WHERE date >= '2022-10-01 15:20:05' AND string ILIKE 'a string with a single quote\''
重要-- 服务器端绑定仅受(ClickHouse 服务器)SELECT
查询支持。它不适用于ALTER
、DELETE
、INSERT
或其他类型的查询。这在未来可能会改变,请参阅https://github.com/ClickHouse/ClickHouse/issues/42092。
客户端绑定
ClickHouse Connect 还支持客户端参数绑定,这可以使生成模板化 SQL 查询更加灵活。对于客户端绑定,parameters
参数应为字典或序列。客户端绑定使用 Python “printf”样式 字符串格式化进行参数替换。
请注意,与服务器端绑定不同,客户端绑定不适用于数据库标识符(如数据库、表或列名),因为 Python 样式格式化无法区分不同类型的字符串,并且需要以不同的方式格式化(反引号或双引号用于数据库标识符,单引号用于数据值)。
- 使用 Python 字典、DateTime 值和字符串转义的示例。
import datetime
my_date = datetime.datetime(2022, 10, 1, 15, 20, 5)
parameters = {'v1': my_date, 'v2': "a string with a single quote'"}
client.query('SELECT * FROM some_table WHERE date >= %(v1)s AND string ILIKE %(v2)s', parameters=parameters)
# Generates the following query:
# SELECT * FROM some_table WHERE date >= '2022-10-01 15:20:05' AND string ILIKE 'a string with a single quote\''
- 使用 Python 序列(元组)、Float64 和 IPv4Address 的示例。
import ipaddress
parameters = (35200.44, ipaddress.IPv4Address(0x443d04fe))
client.query('SELECT * FROM some_table WHERE metric >= %s AND ip_address = %s', parameters=parameters)
# Generates the following query:
# SELECT * FROM some_table WHERE metric >= 35200.44 AND ip_address = '68.61.4.254''
要绑定 DateTime64 参数(具有亚秒精度的 ClickHouse 类型),需要两种自定义方法之一。
将 Python
datetime.datetime
值包装在新的 DT64Param 类中,例如。query = 'SELECT {p1:DateTime64(3)}' # Server side binding with dictionary
parameters={'p1': DT64Param(dt_value)}
query = 'SELECT %s as string, toDateTime64(%s,6) as dateTime' # Client side binding with list
parameters=['a string', DT64Param(datetime.now())]- 如果使用参数值的字典,请在参数名称后附加字符串
_64
。
query = 'SELECT {p1:DateTime64(3)}, {a1:Array(DateTime(3))}' # Server side binding with dictionary
parameters={'p1_64': dt_value, 'a1_64': [dt_value1, dt_value2]}- 如果使用参数值的字典,请在参数名称后附加字符串
设置参数
所有关键的 ClickHouse Connect 客户端“insert”和“select”方法都接受一个可选的settings
关键字参数,以传递 ClickHouse 服务器用户设置 用于包含的 SQL 语句。settings
参数应为字典。每个项目都应为 ClickHouse 设置名称及其关联值。请注意,在作为查询参数发送到服务器时,值将转换为字符串。
与客户端级别设置一样,ClickHouse Connect 将删除服务器标记为readonly=1的任何设置,并附带相应的日志消息。仅适用于通过 ClickHouse HTTP 接口进行查询的设置始终有效。这些设置在get_client
API中进行了描述。
使用 ClickHouse 设置的示例。
settings = {'merge_tree_min_rows_for_concurrent_read': 65535,
'session_id': 'session_1234',
'use_skip_indexes': False}
client.query("SELECT event_type, sum(timeout) FROM event_errors WHERE event_time > '2022-08-01'", settings=settings)
客户端command方法
使用Client.command
方法将 SQL 查询发送到 ClickHouse 服务器,这些查询通常不返回数据或返回单个基本值或数组值而不是完整的数据集。此方法采用以下参数。
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
cmd | str | 必需 | 返回单个值或单个值行的 ClickHouse SQL 语句。 |
参数 | 字典或可迭代对象 | 无 | 参见参数说明。 |
数据 | 字符串或字节 | 无 | 要与命令一起作为 POST 正文包含的可选数据。 |
设置 | 字典 | 无 | 参见设置说明。 |
使用数据库 | 布尔值 | True | 使用客户端数据库(在创建客户端时指定)。False 表示命令将使用连接用户的默认 ClickHouse 服务器数据库。 |
外部数据 | ExternalData | 无 | 包含要与查询一起使用的文件或二进制数据的 ExternalData 对象。参见高级查询(外部数据) |
- command可用于 DDL 语句。如果 SQL“command”不返回数据,则会改为返回“查询摘要”字典。此字典封装了 ClickHouse X-ClickHouse-Summary 和 X-ClickHouse-Query-Id 标头,包括键/值对
written_rows
、written_bytes
和query_id
。
client.command('CREATE TABLE test_command (col_1 String, col_2 DateTime) Engine MergeTree ORDER BY tuple()')
client.command('SHOW CREATE TABLE test_command')
Out[6]: 'CREATE TABLE default.test_command\\n(\\n `col_1` String,\\n `col_2` DateTime\\n)\\nENGINE = MergeTree\\nORDER BY tuple()\\nSETTINGS index_granularity = 8192'
- command也可用于仅返回单行的简单查询。
result = client.command('SELECT count() FROM system.tables')
result
Out[7]: 110
客户端query方法
Client.query
方法是从 ClickHouse 服务器检索单个“批处理”数据集的主要方法。它利用通过 HTTP 传输大型数据集(最多约一百万行)的高效本机 ClickHouse 格式。此方法采用以下参数。
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
查询 | str | 必需 | ClickHouse SQL SELECT 或 DESCRIBE 查询。 |
参数 | 字典或可迭代对象 | 无 | 参见参数说明。 |
设置 | 字典 | 无 | 参见设置说明。 |
查询格式 | 字典 | 无 | 结果值的 datatype 格式规范。请参阅高级用法(读取格式)。 |
列格式 | 字典 | 无 | 每个列的 datatype 格式。请参阅高级用法(读取格式)。 |
编码 | str | 无 | 用于将 ClickHouse 字符串列编码为 Python 字符串的编码。如果未设置,Python 默认为UTF-8 。 |
使用 None | 布尔值 | True | 对于 ClickHouse 空值,使用 Python None 类型。如果为 False,则对于 ClickHouse 空值,使用 datatype 默认值(如 0)。注意 - 出于性能原因,对于 numpy/Pandas 默认为 False。 |
面向列 | 布尔值 | False | 将结果作为列序列而不是行序列返回。有助于将 Python 数据转换为其他面向列的数据格式。 |
查询时区 | str | 无 | 来自 zoneinfo 数据库的时区名称。此时区将应用于查询返回的所有日期时间或 Pandas 时间戳对象。 |
列时区 | 字典 | 无 | 列名称到时区名称的字典。类似于query_tz ,但允许为不同的列指定不同的时区。 |
使用扩展数据类型 | 布尔值 | True | 使用 Pandas 扩展数据类型(如 StringArray),以及 pandas.NA 和 pandas.NaT 来表示 ClickHouse 的 NULL 值。仅适用于 query_df 和 query_df_stream 方法。 |
外部数据 | ExternalData | 无 | 包含要与查询一起使用的文件或二进制数据的 ExternalData 对象。参见高级查询(外部数据) |
上下文 | 查询上下文 (QueryContext) | 无 | 可重用的 QueryContext 对象可以用来封装上述方法参数。请参见 高级查询 (QueryContexts) |
QueryResult 对象
基本 query
方法返回一个 QueryResult 对象,具有以下公共属性
result_rows
-- 以行序列形式返回的数据矩阵,其中每一行元素都是一个列值的序列。result_columns
-- 以列序列形式返回的数据矩阵,其中每一列元素都是该列的行值的序列。column_names
-- 表示result_set
中列名的字符串元组。column_types
-- 表示result_columns
中每一列的 ClickHouse 数据类型的 ClickHouseType 实例元组。query_id
-- ClickHouse 查询 ID(用于在system.query_log
表中检查查询)。summary
--X-ClickHouse-Summary
HTTP 响应头返回的任何数据。first_item
-- 用于将响应的第一行作为字典检索的便利属性(键是列名)。first_row
-- 用于返回结果集第一行的便利属性。column_block_stream
-- 以列方向格式生成查询结果的生成器。不应直接引用此属性(见下文)。row_block_stream
-- 以行方向格式生成查询结果的生成器。不应直接引用此属性(见下文)。rows_stream
-- 生成查询结果的生成器,每次调用产生一行。不应直接引用此属性(见下文)。summary
-- 如command
方法中所述,ClickHouse 返回的摘要信息字典。
*_stream
属性返回一个 Python 上下文,可以用作返回数据的迭代器。只能通过 Client 的 *_stream
方法间接访问它们。
流式查询结果(使用 StreamContext 对象)的完整细节在 高级查询 (Streaming Queries) 中概述。
使用 NumPy、Pandas 或 Arrow 使用查询结果
主 query
方法有三个专门版本
query_np
-- 此版本返回 NumPy 数组,而不是 ClickHouse Connect QueryResult。query_df
-- 此版本返回 Pandas DataFrame,而不是 ClickHouse Connect QueryResult。query_arrow
-- 此版本返回 PyArrow 表。它直接使用 ClickHouse 的Arrow
格式,因此它只接受与主query
方法相同的三个参数:query
、parameters
和settings
。此外,还有一个额外的参数use_strings
,它决定了 Arrow 表是否将 ClickHouse 字符串类型呈现为字符串(如果为 True)或字节(如果为 False)。
客户端流式查询方法
ClickHouse Connect 客户端提供了多种方法来以流的形式检索数据(实现为 Python 生成器)。
query_column_block_stream
-- 以块的形式返回查询数据,作为使用原生 Python 对象的列序列。query_row_block_stream
-- 以行的块的形式返回查询数据,使用原生 Python 对象。query_rows_stream
-- 以行的序列的形式返回查询数据,使用原生 Python 对象。query_np_stream
-- 将 ClickHouse 的每个查询数据块作为 NumPy 数组返回。query_df_stream
-- 将 ClickHouse 的每个查询数据块作为 Pandas DataFrame 返回。query_arrow_stream
-- 以 PyArrow RecordBlocks 的形式返回查询数据。
这些方法中的每一个都返回一个 ContextStream
对象,该对象必须通过 with
语句打开才能开始使用流。有关详细信息和示例,请参见 高级查询 (Streaming Queries)。
客户端 insert 方法
对于将多个记录插入 ClickHouse 的常见用例,可以使用 Client.insert
方法。它接受以下参数
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
表 (table) | str | 必需 | 要插入的 ClickHouse 表。允许使用完整表名(包括数据库)。 |
数据 | 序列的序列 (Sequence of Sequences) | 必需 | 要插入的数据矩阵,可以是行序列(其中每一行都是列值的序列),也可以是列序列(其中每一列都是行值的序列)。 |
列名 (column_names) | 字符串序列或字符串 (Sequence of str, or str) | '*' | 数据矩阵的列名列表。如果使用 '*' 代替,ClickHouse Connect 将执行“预查询”以检索表的所有列名。 |
数据库 | str | '' | 插入的目标数据库。如果未指定,将假定使用客户端的数据库。 |
列类型 (column_types) | ClickHouseType 序列 (Sequence of ClickHouseType) | 无 | ClickHouseType 实例列表。如果既未指定 column_types 也未指定 column_type_names ,ClickHouse Connect 将执行“预查询”以检索表的所有列类型。 |
列类型名称 (column_type_names) | ClickHouse 类型名称序列 (Sequence of ClickHouse type names) | 无 | ClickHouse 数据类型名称列表。如果既未指定 column_types 也未指定 column_type_names ,ClickHouse Connect 将执行“预查询”以检索表的所有列类型。 |
面向列 | 布尔值 | False | 如果为 True,则假定 data 参数为列序列(并且不需要“旋转”来插入数据)。否则,data 将被解释为行序列。 |
设置 | 字典 | 无 | 参见设置说明。 |
插入上下文 (insert_context) | 插入上下文 (InsertContext) | 无 | 可重用的 InsertContext 对象可以用来封装上述方法参数。请参见 高级插入 (InsertContexts) |
此方法返回一个“查询摘要”字典,如“命令”方法中所述。如果插入由于任何原因失败,将引发异常。
主 insert
方法有两个专门版本
insert_df
-- 此方法的第二个参数不要求 Python 序列的序列data
参数,而是要求一个df
参数,该参数必须是 Pandas DataFrame 实例。ClickHouse Connect 自动将 DataFrame 作为列方向数据源处理,因此不需要或不提供column_oriented
参数。insert_arrow
-- 此方法不要求 Python 序列的序列data
参数,而是要求一个arrow_table
。ClickHouse Connect 将 Arrow 表未经修改地传递给 ClickHouse 服务器进行处理,因此除了table
和arrow_table
之外,只有database
和settings
参数可用。
注意:NumPy 数组是有效的序列的序列,可以用作主 insert
方法的 data
参数,因此不需要专门的方法。
文件插入
clickhouse_connect.driver.tools
包含 insert_file
方法,该方法允许将数据直接从文件系统插入到现有的 ClickHouse 表中。解析委托给 ClickHouse 服务器。insert_file
接受以下参数
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
客户端 (client) | 客户端 (Client) | 必需 | 用于执行插入的 driver.Client 。 |
表 (table) | str | 必需 | 要插入的 ClickHouse 表。允许使用完整表名(包括数据库)。 |
文件路径 (file_path) | str | 必需 | 数据文件的本地文件系统路径。 |
格式 (fmt) | str | CSV、CSVWithNames | 文件的 ClickHouse 输入格式。如果未提供 column_names ,则假定为 CSVWithNames。 |
列名 (column_names) | 字符串序列 (Sequence of str) | 无 | 数据文件中的列名列表。对于包含列名的格式不需要。 |
数据库 | str | 无 | 表的数据库。如果表是完全限定的,则忽略。如果未指定,则插入将使用客户端数据库。 |
设置 | 字典 | 无 | 参见设置说明。 |
压缩 (compression) | str | 无 | 用于 Content-Encoding HTTP 标头的已识别的 ClickHouse 压缩类型(zstd、lz4、gzip)。 |
对于数据或日期/时间值格式不一致的文件,此方法会识别适用于数据导入的设置(如 input_format_allow_errors_num
和 input_format_allow_errors_num
)。
import clickhouse_connect
from clickhouse_connect.driver.tools import insert_file
client = clickhouse_connect.get_client()
insert_file(client, 'example_table', 'my_data.csv',
settings={'input_format_allow_errors_ratio': .2,
'input_format_allow_errors_num': 5})
将查询结果保存为文件
可以使用 raw_stream
方法将文件直接从 ClickHouse 流式传输到本地文件系统。例如,如果要将查询结果保存到 CSV 文件,可以使用以下代码段
import clickhouse_connect
if __name__ == '__main__':
client = clickhouse_connect.get_client()
query = 'SELECT number, toString(number) AS number_as_str FROM system.numbers LIMIT 5'
fmt = 'CSVWithNames' # or CSV, or CSVWithNamesAndTypes, or TabSeparated, etc.
stream = client.raw_stream(query=query, fmt=fmt)
with open("output.csv", "wb") as f:
for chunk in stream:
f.write(chunk)
上面的代码将生成一个 output.csv
文件,其内容如下
"number","number_as_str"
0,"0"
1,"1"
2,"2"
3,"3"
4,"4"
类似地,可以将数据保存为 TabSeparated 和其他格式。有关所有可用格式选项的概述,请参见 输入和输出数据格式。
原始 API
对于不需要在 ClickHouse 数据与原生或第三方数据类型和结构之间进行转换的用例,ClickHouse Connect 客户端提供了两种直接使用 ClickHouse 连接的方法。
客户端 raw_query 方法
Client.raw_query
方法允许使用客户端连接直接使用 ClickHouse HTTP 查询接口。返回值是未处理的 bytes
对象。它提供了一个方便的包装器,具有参数绑定、错误处理、重试和使用最小接口的设置管理功能。
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
查询 | str | 必需 | 任何有效的 ClickHouse 查询。 |
参数 | 字典或可迭代对象 | 无 | 参见参数说明。 |
设置 | 字典 | 无 | 参见设置说明。 |
格式 (fmt) | str | 无 | 结果字节的 ClickHouse 输出格式。(如果未指定,ClickHouse 使用 TSV)。 |
使用数据库 | 布尔值 | True | 将 clickhouse-connect 客户端分配的数据库用于查询上下文。 |
外部数据 | ExternalData | 无 | 包含要与查询一起使用的文件或二进制数据的 ExternalData 对象。参见高级查询(外部数据) |
处理结果 bytes
对象是调用者的责任。请注意,Client.query_arrow
只是使用 ClickHouse Arrow
输出格式对此方法进行的简单包装。
客户端 raw_stream 方法
Client.raw_stream
方法与 raw_query
方法具有相同的 API,但返回一个 io.IOBase
对象,该对象可以用作 bytes
对象的生成器/流源。它目前由 query_arrow_stream
方法使用。
客户端 raw_insert 方法
Client.raw_insert
方法允许使用客户端连接直接插入 bytes
对象或 bytes
对象生成器。因为它不对插入有效负载进行任何处理,所以性能非常高。该方法提供选项来指定设置和插入格式。
参数 | 类型 | 默认值 | 描述 |
---|---|---|---|
表 (table) | str | 必需 | 简单表名或数据库限定表名。 |
列名 (column_names) | 序列 (Sequence)[str] | 无 | 插入块的列名。如果 fmt 参数不包含名称,则需要。 |
插入块 (insert_block) | str、bytes、Generator[bytes]、BinaryIO | 必需 | 要插入的数据。字符串将使用客户端编码进行编码。 |
设置 | 字典 | 无 | 参见设置说明。 |
格式 (fmt) | str | 无 | insert_block 字节的 ClickHouse 输入格式。(如果未指定,ClickHouse 使用 TSV)。 |
确保 insert_block
采用指定的格式并使用指定的压缩方法是调用者的责任。ClickHouse Connect 将这些原始插入用于文件上传和 PyArrow 表,并将解析委托给 ClickHouse 服务器。
实用程序类和函数
以下类和函数也被认为是“公共”clickhouse-connect
API 的一部分,并且与上面记录的类和方法一样,在次要版本之间保持稳定。对这些类和函数的重大更改只会出现在次要(而非修补程序)版本中,并且至少在一个次要版本中将以弃用状态提供。
异常
所有自定义异常(包括在 DB API 2.0 规范中定义的异常)都在clickhouse_connect.driver.exceptions
模块中定义。驱动程序实际检测到的异常将使用这些类型之一。
Clickhouse SQL 实用程序
clickhouse_connect.driver.binding
模块中的函数和 DT64Param 类可用于正确构建和转义 ClickHouse SQL 查询。类似地,clickhouse_connect.driver.parser
模块中的函数可用于解析 ClickHouse 数据类型名称。
多线程、多进程和异步/事件驱动用例
ClickHouse Connect 在多线程、多进程和事件循环驱动/异步应用程序中运行良好。所有查询和插入处理都在单个线程内发生,因此操作通常是线程安全的。(某些操作在底层进行并行处理是未来可能增强性能的改进,以克服单线程的性能损失,但即使在这种情况下,也将保持线程安全)。
由于每个查询或插入分别在其自己的 QueryContext 或 InsertContext 对象中维护状态,因此这些辅助对象不是线程安全的,并且不应在多个处理流之间共享。请参阅以下部分中关于上下文对象的更多讨论。
此外,在同时有两个或多个查询和/或插入“正在进行”的应用程序中,还需要考虑另外两个方面。第一个是与查询/插入关联的 ClickHouse“会话”,第二个是 ClickHouse Connect 客户端实例使用的 HTTP 连接池。
AsyncClient 包装器
从 0.7.16 版本开始,ClickHouse Connect 提供了一个常规Client
的异步包装器,以便可以在asyncio
环境中使用客户端。
要获取AsyncClient
的实例,可以使用get_async_client
工厂函数,它接受与标准get_client
相同的参数。
import asyncio
import clickhouse_connect
async def main():
client = await clickhouse_connect.get_async_client()
result = await client.query("SELECT name FROM system.databases LIMIT 1")
print(result.result_rows)
asyncio.run(main())
AsyncClient
具有与标准Client
相同的方法和相同的参数,但在适用时它们是协程。在内部,执行 I/O 操作的这些来自Client
的方法被包装在一个run_in_executor调用中。
使用AsyncClient
包装器时,多线程性能将会提高,因为在等待 I/O 操作完成时,执行线程和 GIL 将被释放。
注意:与常规Client
不同,AsyncClient
默认强制autogenerate_session_id
为False
。
另请参阅:run_async 示例。
管理 ClickHouse 会话 ID
每个 ClickHouse 查询都发生在 ClickHouse“会话”的上下文中。会话目前用于两个目的。
默认情况下,使用 ClickHouse Connect 客户端实例执行的每个查询都使用相同的会话 ID 来启用此会话功能。也就是说,当使用单个 ClickHouse 客户端时,SET
语句和临时表按预期工作。但是,根据设计,ClickHouse 服务器不允许在同一会话中并发查询。因此,对于将执行并发查询的 ClickHouse Connect 应用程序,有两个选项。
- 为每个将拥有其自身会话 ID 的执行线程(线程、进程或事件处理程序)创建一个单独的
Client
实例。这通常是最佳方法,因为它保留了每个客户端的会话状态。 - 为每个查询使用唯一的会话 ID。这避免了在不需要临时表或共享会话设置的情况下出现并发会话问题。(在创建客户端时也可以提供共享设置,但这些设置会随每个请求一起发送,而不是与会话关联)。唯一的 session_id 可以添加到每个请求的
settings
字典中,或者可以禁用autogenerate_session_id
公共设置。
from clickhouse_connect import common
common.set_setting('autogenerate_session_id', False) # This should always be set before creating a client
client = clickhouse_connect.get_client(host='somehost.com', user='dbuser', password=1234)
在这种情况下,ClickHouse Connect 不会发送任何会话 ID,并且 ClickHouse 服务器将生成一个随机的会话 ID。同样,临时表和会话级设置将不可用。
自定义 HTTP 连接池
ClickHouse Connect 使用urllib3
连接池来处理与服务器的底层 HTTP 连接。默认情况下,所有客户端实例共享相同的连接池,这对于大多数用例来说已经足够了。此默认池最多维护 8 个到应用程序使用的每个 ClickHouse 服务器的 HTTP 保持活动连接。
对于大型多线程应用程序,可能需要单独的连接池。自定义连接池可以作为pool_mgr
关键字参数提供给主clickhouse_connect.get_client
函数。
import clickhouse_connect
from clickhouse_connect.driver import httputil
big_pool_mgr = httputil.get_pool_manager(maxsize=16, num_pools=12)
client1 = clickhouse_connect.get_client(pool_mgr=big_pool_mgr)
client2 = clickhouse_connect.get_client(pool_mgr=big_pool_mgr)
如上述示例所示,客户端可以共享池管理器,或者可以为每个客户端创建一个单独的池管理器。有关创建 PoolManager 时可用选项的更多详细信息,请参阅urllib3 文档。
使用 ClickHouse Connect 查询数据:高级用法
QueryContexts
ClickHouse Connect 在 QueryContext 中执行标准查询。QueryContext 包含用于构建针对 ClickHouse 数据库的查询的关键结构,以及用于将结果处理成 QueryResult 或其他响应数据结构的配置。其中包括查询本身、参数、设置、读取格式和其他属性。
可以使用客户端的create_query_context
方法获取 QueryContext。此方法采用与核心查询方法相同的参数。然后,此查询上下文可以作为context
关键字参数传递给query
、query_df
或query_np
方法,而不是传递这些方法的任何或所有其他参数。请注意,为方法调用指定的其他参数将覆盖 QueryContext 的任何属性。
QueryContext 最清晰的用例是使用不同的绑定参数值发送相同的查询。可以通过使用字典调用QueryContext.set_parameters
方法更新所有参数值,或者可以通过使用所需的key
、value
对调用QueryContext.set_parameter
方法更新任何单个值。
client.create_query_context(query='SELECT value1, value2 FROM data_table WHERE key = {k:Int32}',
parameters={'k': 2},
column_oriented=True)
result = client.query(context=qc)
assert result.result_set[1][0] == 'second_value2'
qc.set_parameter('k', 1)
result = test_client.query(context=qc)
assert result.result_set[1][0] == 'first_value2'
请注意,QueryContexts 不是线程安全的,但可以在多线程环境中通过调用QueryContext.updated_copy
方法获取副本。
流式查询
数据块
ClickHouse Connect 将主query
方法中的所有数据处理为从 ClickHouse 服务器接收到的块流。这些块以自定义的“Native”格式在 ClickHouse 之间传输。一个“块”只是一个二进制数据列的序列,其中每个列包含指定数据类型相同数量的数据值。(作为列式数据库,ClickHouse 以类似的形式存储此数据。)从查询返回的块的大小受两个用户设置控制,这些设置可以在多个级别(用户配置文件、用户、会话或查询)设置。它们是
- max_block_size -- 块中行的数量限制。默认值为 65536。
- preferred_block_size_bytes -- 块中字节大小的软限制。默认值为 1,000,0000。
无论preferred_block_size_setting
如何,每个块的行数都不会超过max_block_size
。根据查询的类型,返回的实际块可以是任何大小。例如,覆盖许多分片的分布式表的查询可能包含从每个分片直接检索到的较小块。
当使用 Client 的某个query_*_stream
方法时,结果将按块为基础返回。ClickHouse Connect 每次仅加载一个块。这允许处理大量数据,而无需将大型结果集的所有内容加载到内存中。请注意,应用程序应准备好处理任意数量的块,并且无法控制每个块的确切大小。
HTTP 数据缓冲区用于缓慢处理
由于 HTTP 协议的限制,如果块的处理速度明显慢于 ClickHouse 服务器流式传输数据的速度,则 ClickHouse 服务器将关闭连接,导致在处理线程中抛出异常。可以使用公共http_buffer_size
设置增加 HTTP 流式缓冲区的缓冲区大小(默认为 10 兆字节)来缓解其中一些问题。如果应用程序有足够的可用内存,则在这种情况下使用较大的http_buffer_size
值应该没问题。如果使用lz4
或zstd
压缩,则缓冲区中的数据将被压缩存储,因此使用这些压缩类型将增加可用的总缓冲区。
StreamContexts
每个query_*_stream
方法(如query_row_block_stream
)都返回一个 ClickHouse StreamContext
对象,它是一个组合的 Python 上下文/生成器。这是基本用法。
with client.query_row_block_stream('SELECT pickup, dropoff, pickup_longitude, pickup_latitude FROM taxi_trips') as stream:
for block in stream:
for row in block:
<do something with each row of Python trip data>
请注意,尝试在没有使用with
语句的情况下使用StreamContext会引发错误。使用Python上下文可以确保即使没有使用所有数据和/或在处理过程中引发异常,流(在本例中为流式HTTP响应)也会被正确关闭。此外,StreamContexts只能用于一次消费流。尝试在StreamContext退出后使用它将产生一个StreamClosedError
。
您可以使用StreamContext的source
属性访问父QueryResult
对象,其中包含列名和类型。
流类型
query_column_block_stream
方法将块作为一系列以原生Python数据类型存储的列数据返回。使用上述taxi_trips
查询,返回的数据将是一个列表,其中列表的每个元素是另一个列表(或元组),包含关联列的所有数据。因此block[0]
将是一个仅包含字符串的元组。面向列的格式最常用于对列中的所有值执行聚合操作,例如将总票价加起来。
query_row_block_stream
方法将块作为一系列行返回,就像传统的关联数据库一样。对于出租车行程,返回的数据将是一个列表,其中列表的每个元素是另一个列表,表示一行数据。因此block[0]
将包含第一趟出租车的所有字段(按顺序),block[1]
将包含第二趟出租车的所有字段的行,依此类推。面向行的结果通常用于显示或转换过程。
query_row_stream
是一个便利方法,在遍历流时会自动移至下一个块。否则,它与query_row_block_stream
相同。
query_np_stream
方法将每个块作为二维Numpy数组返回。在内部,Numpy数组(通常)按列存储,因此不需要单独的行或列方法。Numpy数组的“形状”将表示为(列,行)。Numpy库提供了许多操作Numpy数组的方法。请注意,如果查询中的所有列共享相同的Numpy数据类型,则返回的Numpy数组也将只有一个数据类型,并且可以在不实际更改其内部结构的情况下重新整形/旋转。
query_df_stream
方法将每个ClickHouse块作为二维Pandas Dataframe返回。以下是一个示例,它显示了StreamContext对象可以延迟方式用作上下文(但只能使用一次)。
最后,query_arrow_stream
方法将ClickHouse ArrowStream
格式的结果作为包装在StreamContext中的pyarrow.ipc.RecordBatchStreamReader返回。流的每次迭代都会返回PyArrow RecordBlock。
df_stream = client.query_df_stream('SELECT * FROM hits')
column_names = df_stream.source.column_names
with df_stream:
for df in df_stream:
<do something with the pandas DataFrame>
读取格式
读取格式控制从客户端query
、query_np
和query_df
方法返回的值的数据类型。(raw_query
和query_arrow
不会修改来自ClickHouse的传入数据,因此格式控制不适用。)例如,如果UUID的读取格式从默认的native
格式更改为备选的string
格式,则UUID
列的ClickHouse查询将作为字符串值返回(使用标准的8-4-4-4-12 RFC 1422格式),而不是Python UUID对象。
任何格式化函数的“数据类型”参数都可以包含通配符。格式是一个单一的字母小写字符串。
读取格式可以在几个级别设置
- 全局设置,使用
clickhouse_connect.datatypes.format
包中定义的方法。这将控制所有查询中已配置数据类型的格式。
from clickhouse_connect.datatypes.format import set_read_format
# Return both IPv6 and IPv4 values as strings
set_read_format('IPv*', 'string')
# Return all Date types as the underlying epoch second or epoch day
set_read_format('Date*', 'int')
- 对于整个查询,使用可选的
query_formats
字典参数。在这种情况下,指定的数据类型(s)的任何列(或子列)都将使用配置的格式。
# Return any UUID column as a string
client.query('SELECT user_id, user_uuid, device_uuid from users', query_formats={'UUID': 'string'})
- 对于特定列中的值,使用可选的
column_formats
字典参数。键是ClickHouse返回的列名,以及数据列的格式或ClickHouse类型名称和查询格式值的二级“格式”字典。此二级字典可用于嵌套列类型,例如元组或映射。
# Return IPv6 values in the `dev_address` column as strings
client.query('SELECT device_id, dev_address, gw_address from devices', column_formats={'dev_address':'string'})
读取格式选项(Python类型)
ClickHouse类型 | 原生Python类型 | 读取格式 | 注释 |
---|---|---|---|
Int[8-64], UInt[8-32] | int | - | |
UInt64 | int | signed | Superset当前不处理大型无符号UInt64值 |
[U]Int[128,256] | int | string | Pandas和Numpy整数类型最大为64位,因此可以将其作为字符串返回 |
Float32 | float | - | 所有Python浮点数在内部均为64位 |
Float64 | float | - | |
Decimal | decimal.Decimal | - | |
String | string | bytes | ClickHouse字符串列没有固有的编码,因此它们也用于可变长度二进制数据 |
FixedString | bytes | string | FixedString是固定大小的字节数组,但有时会被视为Python字符串 |
Enum[8,16] | string | string, int | Python枚举不接受空字符串,因此所有枚举都呈现为字符串或底层整数值。 |
Date | datetime.date | int | ClickHouse将日期存储为自1970年01月01日以来的天数。此值可作为整数使用 |
Date32 | datetime.date | int | 与Date相同,但适用于更广泛的日期范围 |
DateTime | datetime.datetime | int | ClickHouse将DateTime存储为纪元秒。此值可作为整数使用 |
DateTime64 | datetime.datetime | int | Python datetime.datetime的精度限制为微秒。原始的64位整数值可用 |
IPv4 | ipaddress.IPv4Address | string | IP地址可以读作字符串,格式正确的字符串可以插入为IP地址 |
IPv6 | ipaddress.IPv6Address | string | IP地址可以读作字符串,格式正确的字符串可以插入为IP地址 |
Tuple | dict or tuple | tuple, json | 命名元组默认情况下返回字典。命名元组也可以返回为JSON字符串 |
Map | 字典 | - | |
Nested | 序列 (Sequence)[dict] | - | |
UUID | uuid.UUID | string | UUID可以读作按照RFC 4122格式化的字符串 |
JSON | 字典 | string | 默认情况下返回Python字典。string 格式将返回JSON字符串 |
Variant | object | - | 返回存储值的ClickHouse数据类型对应的Python类型 |
Dynamic | object | - | 返回存储值的ClickHouse数据类型对应的Python类型 |
外部数据
ClickHouse查询可以接受任何ClickHouse格式的外部数据。此二进制数据与查询字符串一起发送,用于处理数据。外部数据功能的详细信息在此处。客户端query*
方法接受一个可选的external_data
参数以利用此功能。external_data
参数的值应为clickhouse_connect.driver.external.ExternalData
对象。该对象的构造函数接受以下参数
名称 | 类型 | 描述 |
---|---|---|
文件路径 (file_path) | str | 本地系统路径上文件的路径,从中读取外部数据。file_path 或data 是必需的 |
文件名 | str | 外部数据“文件”的名称。如果未提供,将根据file_path 确定(不带扩展名) |
数据 | bytes | 以二进制形式表示的外部数据(而不是从文件读取)。data 或file_path 是必需的 |
格式 (fmt) | str | 数据的ClickHouse 输入格式。默认为TSV |
类型 | str或str序列 | 外部数据中列数据类型的列表。如果是字符串,则类型应以逗号分隔。types 或structure 是必需的 |
结构 | str或str序列 | 数据中列名+数据类型的列表(请参阅示例)。structure 或types 是必需的 |
MIME类型 | str | 文件的可选MIME类型。目前ClickHouse忽略此HTTP子标头 |
要发送一个包含“电影”数据的外部CSV文件的查询,并将该数据与ClickHouse服务器上已存在的directors
表合并
import clickhouse_connect
from clickhouse_connect.driver.external import ExternalData
client = clickhouse_connect.get_client()
ext_data = ExternalData(file_path='/data/movies.csv',
fmt='CSV',
structure=['movie String', 'year UInt16', 'rating Decimal32(3)', 'director String'])
result = client.query('SELECT name, avg(rating) FROM directors INNER JOIN movies ON directors.name = movies.director GROUP BY directors.name',
external_data=ext_data).result_rows
可以使用add_file
方法将其他外部数据文件添加到初始ExternalData对象中,该方法与构造函数具有相同的参数。对于HTTP,所有外部数据都作为multi-part/form-data
文件上传的一部分传输。
时区
有多种机制可用于将时区应用于ClickHouse DateTime和DateTime64值。在内部,ClickHouse服务器始终将任何DateTime或DateTime64对象存储为一个时区天真的数字,表示自纪元1970-01-01 00:00:00 UTC时间以来的秒数。对于DateTime64值,表示形式可以是自纪元以来的毫秒、微秒或纳秒,具体取决于精度。因此,任何时区信息的应用始终发生在客户端。请注意,这涉及有意义的额外计算,因此在性能关键型应用程序中,建议将DateTime类型视为纪元时间戳,除了用户显示和转换(例如,Pandas时间戳始终是表示纪元纳秒的64位整数以提高性能)。
当在查询中使用时区感知数据类型时 - 特别是Python datetime.datetime
对象 - clickhouse-connect
使用以下优先级规则应用客户端时区
- 如果为查询指定了查询方法参数
client_tzs
,则将应用特定的列时区 - 如果ClickHouse列具有时区元数据(即,它是一种像DateTime64(3, 'America/Denver')这样的类型),则将应用ClickHouse列时区。(请注意,对于ClickHouse版本23.2之前的DateTime列,clickhouse-connect无法获得此时区元数据)
- 如果为查询指定了查询方法参数
query_tz
,则将应用“查询时区”。 - 如果将时区设置应用于查询或会话,则将应用该时区。(此功能尚未在ClickHouse服务器中发布)
- 最后,如果已将客户端
apply_server_timezone
参数设置为True(默认值),则将应用ClickHouse服务器时区。
请注意,如果根据这些规则应用的时区为UTC,则clickhouse-connect
将始终返回一个时区天真的Python datetime.datetime
对象。然后,如果需要,应用程序代码可以将其他时区信息添加到此时区天真的对象中。
使用ClickHouse Connect插入数据:高级用法
InsertContexts
ClickHouse Connect在InsertContext中执行所有插入操作。InsertContext包含发送到客户端insert
方法的所有参数值。此外,当最初构造InsertContext时,ClickHouse Connect会检索插入列的数据类型,以便有效地进行原生格式插入。通过对多个插入操作重用InsertContext,可以避免此“预查询”,并更快、更高效地执行插入操作。
可以使用客户端create_insert_context
方法获取InsertContext。该方法与insert
函数具有相同的参数。请注意,只有InsertContexts的data
属性应在重用时修改。这与其预期的用途一致,即为重复将新数据插入同一表提供可重用的对象。
test_data = [[1, 'v1', 'v2'], [2, 'v3', 'v4']]
ic = test_client.create_insert_context(table='test_table', data='test_data')
client.insert(context=ic)
assert client.command('SELECT count() FROM test_table') == 2
new_data = [[3, 'v5', 'v6'], [4, 'v7', 'v8']]
ic.data = new_data
client.insert(context=ic)
qr = test_client.query('SELECT * FROM test_table ORDER BY key DESC')
assert qr.row_count == 4
assert qr[0][0] == 4
InsertContexts包含在插入过程中更新的可变状态,因此它们不是线程安全的。
写入格式
目前仅对有限数量的数据类型实现了写入格式。在大多数情况下,ClickHouse Connect 会尝试通过检查第一个(非空)数据值的数据类型来自动确定列的正确写入格式。例如,如果插入 DateTime 列,并且该列的第一个插入值为 Python 整数,则 ClickHouse Connect 会直接插入整数,假设它实际上是 epoch 秒。
在大多数情况下,无需覆盖数据类型的写入格式,但可以使用 clickhouse_connect.datatypes.format
包中的相关方法在全局范围内执行此操作。
写入格式选项
ClickHouse类型 | 原生Python类型 | 写入格式 | 注释 |
---|---|---|---|
Int[8-64], UInt[8-32] | int | - | |
UInt64 | int | ||
[U]Int[128,256] | int | ||
Float32 | float | ||
Float64 | float | ||
Decimal | decimal.Decimal | ||
String | string | ||
FixedString | bytes | string | 如果插入为字符串,则其他字节将设置为零 |
Enum[8,16] | string | ||
Date | datetime.date | int | ClickHouse 将日期存储为自 1970/01/01 以来经过的天数。int 类型将被假定为此“纪元日期”值 |
Date32 | datetime.date | int | 与Date相同,但适用于更广泛的日期范围 |
DateTime | datetime.datetime | int | ClickHouse 将 DateTime 存储为 epoch 秒。int 类型将被假定为此“纪元秒”值 |
DateTime64 | datetime.datetime | int | Python datetime.datetime的精度限制为微秒。原始的64位整数值可用 |
IPv4 | ipaddress.IPv4Address | string | 可以将格式正确的字符串插入为 IPv4 地址 |
IPv6 | ipaddress.IPv6Address | string | 可以将格式正确的字符串插入为 IPv6 地址 |
Tuple | dict or tuple | ||
Map | 字典 | ||
Nested | 序列 (Sequence)[dict] | ||
UUID | uuid.UUID | string | 可以将格式正确的字符串插入为 ClickHouse UUID |
JSON/Object('json') | 字典 | string | 可以将字典或 JSON 字符串插入 JSON 列(注意 Object('json') 已弃用) |
Variant | object | 目前所有变体都作为字符串插入,并由 ClickHouse 服务器解析 | |
Dynamic | object | 警告 - 目前,对动态列的任何插入都将作为 ClickHouse 字符串持久化 |
其他选项
ClickHouse Connect 为高级用例提供了一些其他选项
全局设置
有一些设置可以全局控制 ClickHouse Connect 的行为。可以从顶级 common
包中访问它们
from clickhouse_connect import common
common.set_setting('autogenerate_session_id', False)
common.get_setting('invalid_setting_action')
'drop'
这些通用设置 autogenerate_session_id
、product_name
和 readonly
应该始终在使用 clickhouse_connect.get_client
方法创建客户端之前修改。创建客户端后更改这些设置不会影响现有客户端的行为。
目前定义了十个全局设置
设置名称 | 默认值 | 选项 | 描述 |
---|---|---|---|
autogenerate_session_id | True | True, False | 为每个客户端会话自动生成新的 UUID(1) 会话 ID(如果未提供)。如果没有提供会话 ID(在客户端或查询级别),ClickHouse 将为每个查询生成随机的内部 ID |
invalid_setting_action | 'error' | 'drop', 'send', 'error' | 提供无效或只读设置时采取的操作(对于客户端会话或查询)。如果为 drop ,则会忽略该设置;如果为 send ,则会将该设置发送到 ClickHouse;如果为 error ,则会引发客户端 ProgrammingError |
dict_parameter_format | 'json' | 'json', 'map' | 这控制参数化查询是否将 Python 字典转换为 JSON 或 ClickHouse Map 语法。json 应用于插入 JSON 列,map 应用于 ClickHouse Map 列 |
product_name | 一个与查询一起传递给 ClickHouse 的字符串,用于跟踪使用 ClickHouse Connect 的应用程序。应采用以下格式<产品名称;&gl/<产品版本> | ||
max_connection_age | 600 | HTTP 保持活动连接保持打开/重用状态的最大秒数。这可以防止连接集中到负载均衡器/代理后面的单个 ClickHouse 节点。默认为 10 分钟。 | |
readonly | 0 | 0, 1 | 在 19.17 之前的版本中隐含的“read_only”ClickHouse 设置。可以设置为与 ClickHouse 的“read_only”值匹配,以便与非常旧的 ClickHouse 版本一起操作 |
use_protocol_version | True | True, False | 使用客户端协议版本。这对于 DateTime 时区列是必需的,但会与当前版本的 chproxy 冲突 |
max_error_size | 1024 | 客户端错误消息中将返回的最大字符数。对于此设置,使用 0 以获取完整的 ClickHouse 错误消息。默认为 1024 个字符。 | |
send_os_user | True | True, False | 在发送到 ClickHouse 的客户端信息(HTTP User-Agent 字符串)中包含检测到的操作系统用户 |
http_buffer_size | 10MB | 用于 HTTP 流式查询的“内存中”缓冲区的大小(以字节为单位) |
压缩
ClickHouse Connect 支持 lz4、zstd、brotli 和 gzip 压缩,用于查询结果和插入。始终记住,使用压缩通常需要在网络带宽/传输速度与 CPU 使用率(客户端和服务器端)之间进行权衡。
要接收压缩数据,ClickHouse 服务器的 enable_http_compression
必须设置为 1,或者用户必须具有“每个查询”基础上更改该设置的权限。
压缩由调用 clickhouse_connect.get_client
工厂方法时的 compress
参数控制。默认情况下,compress
设置为 True
,这将触发默认压缩设置。对于使用 query
、query_np
和 query_df
客户端方法执行的查询,ClickHouse Connect 将添加 Accept-Encoding
标头,其中包含 lz4
、zstd
、br
(如果安装了 brotli 库)、gzip
和 deflate
编码,用于使用 query
客户端方法执行的查询(以及间接的 query_np
和 query_df
)。(对于大多数请求,ClickHouse 服务器将返回 zstd
压缩的有效负载。)对于插入,默认情况下,ClickHouse Connect 将使用 lz4
压缩压缩插入块,并发送 Content-Encoding: lz4
HTTP 标头。
get_client
的 compress
参数还可以设置为特定的压缩方法,即 lz4
、zstd
、br
或 gzip
之一。然后,该方法将用于插入和查询结果(如果 ClickHouse 服务器支持)。现在,ClickHouse Connect 默认安装了所需的 zstd
和 lz4
压缩库。如果指定了 br
/brotli,则必须单独安装 brotli 库。
请注意,raw*
客户端方法不使用客户端配置指定的压缩。
我们也不建议使用 gzip
压缩,因为它在压缩和解压缩数据方面都比其他方法慢得多。
HTTP 代理支持
ClickHouse Connect 使用 urllib3 库添加了基本的 HTTP 代理支持。它识别标准的 HTTP_PROXY
和 HTTPS_PROXY
环境变量。请注意,使用这些环境变量将应用于使用 clickhouse_connect.get_client
方法创建的任何客户端。或者,要配置每个客户端,可以使用 http_proxy
或 https_proxy
参数传递给 get_client 方法。有关 HTTP 代理支持实现的详细信息,请参阅urllib3 文档。
要使用 Socks 代理,可以将 urllib3 SOCKSProxyManager 作为 pool_mgr
参数发送给 get_client
。请注意,这需要直接安装 PySocks 库,或者使用 urllib3 依赖项的 [socks]
选项安装。
“旧”JSON 数据类型
实验性的 Object
(或 Object('json')
)数据类型已弃用,应避免在生产环境中使用。ClickHouse Connect 继续为该数据类型提供有限的支持以实现向后兼容。请注意,此支持不包括预期将“顶级”或“父级”JSON 值作为字典或等效值返回的查询,此类查询将导致异常。
“新”变体/动态/JSON 数据类型(实验性功能)
从 0.8.0 版本开始,clickhouse-connect
为新的(也为实验性的)ClickHouse 类型 Variant、Dynamic 和 JSON 提供了实验性支持。
使用说明
- JSON 数据可以插入为 Python 字典或包含 JSON 对象
{}
的 JSON 字符串。不支持其他形式的 JSON 数据 - 使用这些类型的子列/路径的查询将返回子列的类型。
- 有关其他使用说明,请参阅 ClickHouse 主文档
已知限制:
- 在使用之前,必须在 ClickHouse 设置中启用这些类型中的每一个。
- “新”JSON 类型从 ClickHouse 24.8 版本开始可用
- 由于内部格式更改,
clickhouse-connect
仅与 ClickHouse 24.7 版本开始的 Variant 类型兼容 - 返回的 JSON 对象将仅返回
max_dynamic_paths
个元素(默认为 1024)。这将在将来的版本中修复。 - 对
Dynamic
列的插入始终将是 Python 值的字符串表示形式。这将在将来的版本中修复,一旦https://github.com/ClickHouse/ClickHouse/issues/70395 已修复。 - 新类型的实现尚未在 C 代码中进行优化,因此性能可能比更简单、更成熟的数据类型慢一些。