跳转到主要内容

描述

pg_clickhouse 是一个 PostgreSQL 扩展,可在 ClickHouse 数据库上远程执行查询, 其中包括一个[外部数据包装器]。它支持 PostgreSQL 13 及以上版本,以及 ClickHouse 23 及以上版本。

快速开始

试用 pg_clickhouse 最简单的方式是使用 [Docker 镜像],其中包含 标准的 PostgreSQL Docker 镜像,并集成了 pg_clickhouse 和 [re2][re2 扩展] 扩展:
请参阅教程,开始了解如何导入 ClickHouse 表并下推查询。

用法

版本策略

pg_clickhouse 的公开发布版本遵循[语义化版本控制]。
  • API 发生变更时,递增主版本号
  • SQL 发生向后兼容的变更时,递增次版本号
  • 仅有 binary 变更时,递增补丁版本号
安装后,PostgreSQL 会跟踪两种版本形式:
  • 库版本 (在 PostgreSQL 18 及以上版本中由 PG_MODULE_MAGIC 定义) 包含完整的语义化版本号,可在 pgch_version() 函数的输出或 Postgres pg_get_loaded_modules() 函数中查看。
  • 扩展版本 (在控制文件中定义) 仅包含主版本号和次版本号,可在 pg_catalog.pg_extension 表、pg_available_extension_versions() 函数的输出以及 \dx pg_clickhouse 中查看。
在实际使用中,这意味着补丁版本号递增的发布 (例如从 v0.1.0 升级到 v0.1.1) 会让所有已加载 v0.1 的数据库直接受益,无需运行 ALTER EXTENSION 即可获得升级内容。 相反,次版本号或主版本号递增的发布会附带 SQL 升级脚本,所有包含该扩展的现有数据库都必须运行 ALTER EXTENSION pg_clickhouse UPDATE 才能获得升级内容。

DDL SQL 参考

以下 SQL DDL 表达式使用 pg_clickhouse。

CREATE EXTENSION

使用 CREATE EXTENSION 将 pg_clickhouse 扩展添加到数据库中:
使用 WITH SCHEMA 将其安装到指定的 schema 中 (推荐) :

ALTER EXTENSION

使用 ALTER EXTENSION 修改 pg_clickhouse。示例:
  • 安装 pg_clickhouse 的新 release 后,使用 UPDATE 子句:
  • 使用 SET SCHEMA 将该扩展移动到新的 schema:

DROP EXTENSION

使用 DROP EXTENSION 从数据库中删除 pg_clickhouse:
如果存在任何依赖于 pg_clickhouse 的对象,此命令会失败。请使用 CASCADE 子句将它们一并删除:

CREATE SERVER

使用 CREATE SERVER 创建连接到 ClickHouse 服务器的外部服务器。示例:
支持的选项有:
  • driver:要使用的 ClickHouse 连接驱动程序,可以是 “binary” 或 “http”。必填。
  • dbname:连接时使用的 ClickHouse 数据库。默认为 “default”。
  • fetch_size:HTTP streaming 的近似批次大小 (以字节为单位) 。批次 按行边界拆分。默认为 50000000 (50 MB) 。0 会禁用 streaming 并缓冲整个响应。foreign table 可以覆盖此 值。
  • host:ClickHouse server 的主机名。默认为 “localhost”;
  • port:连接到 ClickHouse server 时使用的端口。默认值 如下:
    • 如果 driver 为 “binary” 且 host 是 ClickHouse Cloud 主机,则为 9440
    • 如果 driver 为 “binary” 且 host 不是 ClickHouse Cloud 主机,则为 9004
    • 如果 driver 为 “http” 且 host 是 ClickHouse Cloud 主机,则为 8443
    • 如果 driver 为 “http” 且 host 不是 ClickHouse Cloud 主机,则为 8123

ALTER SERVER

使用 ALTER SERVER 修改 外部服务器。示例:
这些选项与 CREATE SERVER 中的选项相同。

DROP SERVER

使用 DROP SERVER 删除 外部服务器:
如果有任何其他对象依赖于该服务器,此命令将失败。使用 CASCADE 还会 一并删除这些依赖对象:

CREATE USER MAPPING

使用 CREATE USER MAPPING 将 PostgreSQL 用户映射为 ClickHouse 用户。例如,使用 taxi_srv 外部服务器 连接时,可将当前 PostgreSQL 用户映射为远程 ClickHouse 用户:
支持的选项如下:
  • user:ClickHouse 用户名。默认为 “default”。
  • password:ClickHouse 用户的密码。

ALTER USER MAPPING

使用 ALTER USER MAPPING 修改用户映射的定义:
这些选项与 CREATE USER MAPPING 中的选项相同。

DROP USER MAPPING

使用 DROP USER MAPPING 移除用户映射:

IMPORT FOREIGN SCHEMA

使用 IMPORT FOREIGN SCHEMA 可将 ClickHouse 数据库中定义的所有表作为外部表导入到 PostgreSQL schema 中:
使用 LIMIT TO 将导入限制到特定表:
使用 EXCEPT 排除这些表:
pg_clickhouse 将获取指定 ClickHouse 数据库 (上述示例中的 “demo”) 中所有表的列表,获取每个表的列定义, 并执行 CREATE FOREIGN TABLE 命令来创建 外部表。列将使用支持的数据 类型进行定义,并在可检测的情况下使用 CREATE FOREIGN TABLE 支持的选项。
导入标识符的大小写保留IMPORT FOREIGN SCHEMA 会对导入的表名和列名运行 quote_identifier(), 为包含大写字母或空格的标识符加上双引号。 因此,这类表名和列名在 PostgreSQL 查询中必须用双引号括起来。 如果名称全部为小写且不包含空格字符,则无需加引号。例如,给定以下 ClickHouse 表:
IMPORT FOREIGN SCHEMA 会创建这个外部表:
因此,查询中也必须正确加引号,例如:
若要创建名称不同或全部为小写 (因此 不区分大小写) 的对象,请使用 CREATE FOREIGN TABLE

CREATE FOREIGN TABLE

使用 CREATE FOREIGN TABLE 创建可查询 ClickHouse 数据库中数据的外部表:
支持的表选项如下:
  • database:远程 database 的名称。默认使用为 外部服务器 定义的 database。
  • fetch_size:HTTP streaming 的近似批次大小 (以字节为单位) 。会覆盖 server 级别的 fetch_size。默认值为 50000000 (50 MB) 。0 会禁用 流式传输并缓冲完整响应。
  • table_name:远程表的名称。默认使用为 foreign table 指定的名称。
  • engine:ClickHouse 表使用的[表引擎]。对于 CollapsingMergeTree()AggregatingMergeTree(),pg_clickhouse 会自动将参数应用于在该表上执行的函数表达式。
对于每一列,请使用与远程 ClickHouse 数据 类型相对应的data type。支持的列选项如下:
  • column_name:ClickHouse 端的列名,在反解析查询和 插入语句时,会优先使用该名称而不是 PostgreSQL attribute 名称。 这对于将未加引号的小写 PostgreSQL 列名映射到 区分大小写的 ClickHouse 列很有用,例如:
  • AggregateFunction:应用于 AggregateFunction Type 列的聚合函数名称。将数据类型映射为传递给该函数的 ClickHouse 类型,并通过相应的列选项指定 聚合函数名称,pg_clickhouse 会自动在计算该列的聚合函数后追加 Merge
  • SimpleAggregateFunction:应用于 SimpleAggregateFunction Type 列的聚合函数名称。将数据类型映射为 传递给该函数的 ClickHouse 类型,并通过相应的 列选项指定聚合函数名称。

ALTER FOREIGN TABLE

使用 ALTER FOREIGN TABLE 修改外部表的定义:
支持的表和列选项与 CREATE FOREIGN TABLE 中的相同。

DROP FOREIGN TABLE

使用 DROP FOREIGN TABLE 删除外部表:
如果有任何对象依赖于该外部表,此命令将失败。 使用 CASCADE 子句也会将它们一并删除:

DML SQL 参考

下面的 SQL DML 表达式可能会用到 pg_clickhouse。示例基于 以下 ClickHouse 表:

EXPLAIN

EXPLAIN 命令可按预期运行,但 VERBOSE 选项会触发输出 ClickHouse 的 “Remote SQL” 查询:
此查询会通过 “Foreign Scan” 计划节点下推到 ClickHouse,作为远程 SQL 执行。

SELECT

使用 SELECT 语句在 pg_clickhouse 表上执行查询,与在任何其他表上执行查询无异:
pg_clickhouse 会尽可能将查询执行下推到 ClickHouse,包括聚合函数。使用 EXPLAIN 可确定 下推的范围。例如,对于上述查询,所有执行都会下推到 ClickHouse
pg_clickhouse 还会将同一远程服务器上的表之间的 JOIN 下推:
如果不经过仔细调优,与本地表连接会生成效率较低的查询。在这个示例中,我们创建了 nodes 表的一个本地副本,并与它连接,而不是连接远程表:
在这种情况下,我们可以通过 按 node_id 而不是本地列分组,将更多聚合下推到 ClickHouse,然后再 与查找表进行 join:
“Foreign Scan”节点现在会按 node_id 下推聚合,将需要从 Postgres 拉回的行数从 1000 行 (全部行) 减少到仅 8 行,即每个节点 1 行。

PREPARE, EXECUTE, DEALLOCATE

自 v0.1.2 起,pg_clickhouse 支持参数化查询,主要通过 PREPARE 命令创建:
像平常一样使用 EXECUTE 执行预处理语句:
参数化执行会导致 http 驱动 在 25.8 之前的 ClickHouse 版本中 无法正确转换 DateTime 时区,因为该[底层缺陷]当时尚未[修复]。请注意,PostgreSQL 有时即使不使用 PREPARE,也会采用参数化查询计划。对于任何需要精确时区转换的查询, 如果无法升级到 25.8 或更高版本,请改用 binary driver
与往常一样,pg_clickhouse 会下推聚合操作,如 EXPLAIN 的详细输出所示:
请注意,它发送的是完整的日期值,而不是参数占位符。 前五次请求都是如此,如 PostgreSQL [PREPARE 说明] 中所述。到第六次执行时,它会发送 ClickHouse {param:type} 风格的[查询参数]: 参数:
使用 DEALLOCATE 解除分配预处理语句:

INSERT

使用 INSERT 命令向远程 ClickHouse 表中插入值:

COPY

使用 COPY 命令将一个批次的数据行插入远程 ClickHouse 表:
⚠️ 批次 API 的限制 pg_clickhouse 尚未支持 PostgreSQL FDW 的批次 insert API。因此,COPY 目前通过 INSERT 语句 插入记录。后续版本将对此进行改进。

LOAD

使用 LOAD 加载 pg_clickhouse 共享库:
通常不需要使用 LOAD,因为 Postgres 会在首次使用 pg_clickhouse 的任一功能 (函数、外部表等) 时自动加载它。 LOAD pg_clickhouse 可能有用的一种情况是:在执行依赖这些参数的查询之前,先通过 SET 设置 pg_clickhouse 参数。

SET

使用 SET 来设置 pg_clickhouse 的自定义配置参数。

pg_clickhouse.session_settings

pg_clickhouse.session_settings 参数用于配置在后续查询中要设置的 [ClickHouse 设置]。示例:
默认值为 join_use_nulls 1, group_by_use_nulls 1, final 1。将其设为空 字符串即可恢复为 ClickHouse server 的设置。
其语法为由逗号分隔的键/值对列表,各项之间以一个或 多个空格分隔。键必须与 [ClickHouse 设置] 对应。在值中,空格、 逗号和反斜杠都要用反斜杠转义:
或者使用单引号包裹值,以避免转义空格和逗号;也可以考虑 使用[美元引号表示法],这样就无需再使用双引号:
如果你更注重可读性,并且需要设置很多项,可以分成多 行,例如:
当这些设置会干扰 pg_clickhouse 自身运行时,其中一些设置将被忽略。包括:
  • date_time_output_format:http 驱动要求其为 “iso”
  • format_tsv_null_representation:http 驱动要求使用默认值
  • output_format_tsv_crlf_end_of_line:http 驱动要求使用默认值
除此之外,pg_clickhouse 不会校验这些设置,而是会在每次查询时将它们传递给 ClickHouse。因此,它支持各个 ClickHouse 版本中的所有设置。 请注意,必须先加载 pg_clickhouse,才能设置 pg_clickhouse.session_settings;可以使用[共享库预加载],或者 直接使用该扩展中的某个对象以确保其被加载。

pg_clickhouse.pushdown_regex

pg_clickhouse.pushdown_regex 参数用于控制 pg_clickhouse 是否对正则表达式函数和操作符执行下推。默认情况下会执行下推; 将此参数设置为 false 可阻止下推:
详见正则表达式

ALTER ROLE

使用 ALTER ROLESET 命令,可为特定角色预加载 pg_clickhouse, 和/或 SET 其参数:
使用 ALTER ROLE’s RESET 命令重置 pg_clickhouse 的预加载 和/或相关参数:

预加载

如果每个或几乎每个 Postgres 连接都需要使用 pg_clickhouse, 请考虑使用[共享库预加载]来自动加载它:

session_preload_libraries

在每次建立与 PostgreSQL 的新连接时加载共享库:
有助于在不重启服务器的情况下应用更新:只需 重新连接即可。也可以通过 ALTER ROLE 为特定用户或角色设置。

shared_preload_libraries

在启动时将共享库加载到 PostgreSQL 主进程中:
有助于减少每个会话的内存占用和加载开销,但在库更新时需要 重启集群。

数据类型

pg_clickhouse 将以下 ClickHouse 数据类型映射为 PostgreSQL 数据 类型。IMPORT FOREIGN SCHEMA 在导入列时会使用 PostgreSQL 列中的第一种类型;其他类型可在 CREATE FOREIGN TABLE 语句中使用: 更多说明和细节如下。

BYTEA

ClickHouse 不提供与 PostgreSQL BYTEA 类型等效的类型,但允许将任意字节存储在 String 类型中。一般情况下,ClickHouse 字符串应映射到 PostgreSQL 的 TEXT 类型;若需使用二进制数据,则应映射到 BYTEA。示例:
最终的 SELECT 查询将输出:
请注意,如果 ClickHouse 列中存在空字节,使用 TEXT 列的外部表将无法输出正确的值:
输出结果:
请注意,第二行和第三行包含被截断的值。这是因为 PostgreSQL 依赖以 nul 结尾的字符串,且不支持在字符串中 包含 nul 字符。 尝试向 TEXT 列插入二进制值将会成功,并按预期运行:
文本列将显示正确:
但如果按 BYTEA 读取,则不会:
一般来说,TEXT 列只用于编码字符串,BYTEA 列只用于二进制数据, 并且绝不要在两者之间切换。

函数与 operator 参考

函数

这些函数提供了查询 ClickHouse 数据库的接口。

clickhouse_raw_query

通过其 HTTP interface 连接到 ClickHouse 服务,执行单个 查询,然后断开连接。可选的第二个参数用于指定连接 字符串,默认为 host=localhost port=8123。支持的连接 参数如下:
  • host:要连接到的主机;必填。
  • port:要连接的 HTTP 端口;默认为 8123,除非 host 是 ClickHouse Cloud 主机,此时默认值为 8443
  • dbname:要连接到的数据库名称。
  • username:连接时使用的用户名;默认为 default
  • password:用于身份验证的密码;默认无密码
默认情况下,没有任何角色具有对此函数的 EXECUTE 权限;请考虑仅向 确实需要执行临时 ClickHouse 查询的角色 GRANT 此权限, 例如专用的 ClickHouse 管理员角色: 适用于不返回记录的查询,但如果查询确实返回值, 则会作为单个文本值返回:

下推函数

pg_clickhouse 会将条件子句 (HAVINGWHERE 子句) 中使用的部分 PostgreSQL 内置函数下推到 ClickHouse 中执行。该子集与 ClickHouse 中的对应函数如下:

下推操作符

自定义函数

这些由 pg_clickhouse 创建的自定义函数,可为部分在 PostgreSQL 中没有对应实现的 ClickHouse 函数提供外部查询下推。如果其中任何函数无法下推,则会引发异常。

扩展下推

pg_clickhouse 可识别部分核心扩展和第三方扩展中的函数,并将其下推为 ClickHouse 中对应的等效函数。

re2

所有 re2 extension 函数都可 1:1 下推到 ClickHouse:

intarray

有一个 intarray 函数可下推至 ClickHouse:

fuzzystrmatch

两个 fuzzystrmatch 函数可下推至 ClickHouse:

下推类型转换

对于兼容的 数据类型,pg_clickhouse 会下推 CAST(x AS bigint) 这类类型转换。 对于不兼容的类型,下推会失败;例如,如果此示例中的 x 是 ClickHouse 的 UInt64, ClickHouse 会拒绝执行该类型转换。 为了将类型转换下推到不兼容的 数据类型,pg_clickhouse 提供了 以下函数。如果这些函数没有被下推,就会在 PostgreSQL 中引发异常。

聚合函数下推

以下 PostgreSQL 聚合函数可下推到 ClickHouse。

自定义聚合函数

这些由 pg_clickhouse 创建的自定义聚合函数,可为部分在 PostgreSQL 中没有对应函数的 ClickHouse 聚合函数提供外部查询下推。如果这些函数中的任何一个无法下推, 就会引发异常。

下推有序集合聚合函数

这些[有序集合聚合函数]会映射为 ClickHouse 的[参数化 聚合函数]:将其直接参数作为 parameter 传递,并将其 ORDER BY expression 作为 argument。例如,以下 PostgreSQL 查询:
对应的 ClickHouse 查询如下:
请注意,不支持非默认的 ORDER BY 后缀 DESCNULLS FIRST, 使用它们会报错。

下推窗口函数

这些 PostgreSQL [窗口函数] 可以通过 OVER (PARTITION BY ... ORDER BY ...) 子句下推到 ClickHouse;在适用情况下,也包括窗口帧规范。 排名函数 (row_numberrankdense_rankntilecume_distpercent_rank) 在下推时会省略窗口帧子句,因为 ClickHouse 不接受这些函数的窗口帧规范。

兼容性说明

正则表达式

pg_clickhouse.pushdown_regex 为 true (默认值) 时, pg_clickhouse 会将正则表达式下推为 ClickHouse 中的等效形式, 并尽力保证基本兼容性,但你仍需了解二者之间的差异,以及 pg_clickhouse 如何处理这些差异。
  • PostgreSQL 支持 POSIX Regular Expressions,而 ClickHouse 支持 RE2 Regular Expressions。请注意二者在行为上的差异:当正则表达式由 ClickHouse 计算时 (例如在 WHERE 子句中) ,请按 RE2 编写;当它由 Postgres 计算时 (例如在 SELECT 子句中) ,请按 POSIX 编写。
  • pg_clickhouse 会将 Postgres 的 [Regex flags] 预置到 ClickHouse 正则表达式的 (?) 中,以实现下推。例如:
    会变成
    注意这里包含了 -s;这是为了禁用 ClickHouse 默认开启的 s, 以使其行为与 Postgres 正则表达式保持一致。 如果 Postgres 函数调用中的标志包含 s,pg_clickhouse 就不会添加 -s。 不幸的是,这种行为会破坏 Postgres 24 及更早版本中某些正则表达式的兼容性。
  • 两者共同支持、因此可在由 ClickHouse 计算时使用的标志只有:
    • i:不区分大小写
    • m:多行模式:
    • s:让 . 匹配 \n
    • p:部分换行敏感匹配 (按与 s 相同的方式处理)
    • t:严格语法 (默认值,会被 pg_clickhouse 移除)
    RE2 仅支持这些标志;不要使用任何其他 Postgres flags
  • 传递给正则表达式函数的任何其他标志都会导致该 函数无法下推。
  • 例外是 regexp_replace(),它还支持 g 标志。当 设置了 g 时,pg_clickhouse 会使用 replaceRegexpAll() 而不是 replaceRegexpOne(),并在预置其他标志前移除该标志。
  • Postgres 的 regexp_replace() 的 replacement 参数支持使用 \& 表示整个匹配结果,而 ClickHouse 则使用 \0 表示整个 匹配结果。函数下推到 ClickHouse 时,请务必使用 \0
为避免任何歧义,建议设置 pg_clickhouse.pushdown_regex 以阻止 Postgres 正则表达式下推到 ClickHouse,并使用 re2 extension;对于该扩展,pg_clickhouse 支持将 与 ClickHouse 兼容的 RE2 正则表达式进行直接下推

to_char()

PostgreSQL 中用于 timestamptimestamp with time zoneto_char() 仅在 format argument 为非 NULL 的 string constant,且其中每个 PostgreSQL 关键字 在 ClickHouse 中都有一个逐字节完全一致的对应项时,才会下推到 ClickHouse formatDateTime。 如果 format 是动态的 (不是 Const) ,或者包含任何不支持的关键字或 modifier, 则该调用会回退到 PostgreSQL 本地求值——绝不会在部分翻译的情况下尝试下推, 因此输出会保持与 PG 兼容。 用于 numericinterval 及其他非 timestamp 类型的双参数 to_char() 形式永远不会下推;ClickHouse formatDateTime 仅用于格式化日期时间值。

已转换的关键字

带引号的文本和字面量

"..." 包裹的文本会原样传递,其中任何字面的 % 都会写成 %%,以转义 ClickHouse 的格式说明符前缀。引号外的 \" 也会作为字面量 " 原样传递。在 "..." 内部,反斜杠 只会转义 ";其他反斜杠序列都会被视为字面文本。

作者

David E. Wheeler 版权所有 (c) 2025-2026,ClickHouse
最后修改于 2026年6月10日