Skip to main content

描述

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

入门

试用 pg_clickhouse 最简单的方法是使用 Docker image,其中包含 标准的 PostgreSQL Docker 镜像,以及 pg_clickhouse 和 re2 扩展:
请参阅教程,开始导入 ClickHouse 表并 实现查询下推。

用法

版本策略

pg_clickhouse 的公开发布版本遵循[语义化版本控制]。
  • API 发生变更时,主版本号递增
  • 向后兼容的 SQL 变更会递增次版本号
  • 仅涉及二进制文件的变更会递增补丁版本号
安装后,PostgreSQL 会跟踪两个版本变体:
  • 库版本 (在 PostgreSQL 18 及以上版本中由 PG_MODULE_MAGIC 定义) 包含完整的语义化版本号,可在 pgch_version() 函数的输出或 Postgres pg_get_loaded_modules() 函数中查看。
  • 扩展版本 (在 control 文件中定义) 仅包含主版本号 和次版本号,可在 pg_catalog.pg_extension 表中、 pg_available_extension_versions() 函数的输出以及 \dx pg_clickhouse 中查看。
实际上,这意味着补丁版本号递增的 release,例如 从 v0.1.0v0.1.1,会让所有已加载 v0.1 的 数据库直接受益,无需运行 ALTER EXTENSION 即可获得升级后的改进。 另一方面,次版本号或主版本号递增的 release 会附带 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 的新版本后,使用 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 流式传输的近似批次大小 (以字节为单位) 。批次会按 行边界拆分。默认为 50000000 (50 MB) 。0 会禁用 流式传输并缓冲完整响应。外部表可以覆盖该 值。
  • host:ClickHouse 服务器的主机名。默认为 “localhost”;
  • port:连接到 ClickHouse 服务器时使用的端口。默认值 如下:
    • 如果 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:远程数据库的名称。默认使用为 外部服务器 定义的数据库。
  • fetch_size:HTTP streaming 的近似批次大小 (以字节为单位) 。会覆盖 server 级别的 fetch_size。默认值为 50000000 (50 MB) 。0 会禁用 streaming,并缓冲整个响应。
  • table_name:远程表的名称。默认使用为 外部表 指定的名称。
  • engine:ClickHouse 表使用的[表引擎]。对于 CollapsingMergeTree()AggregatingMergeTree(),pg_clickhouse 会自动将参数应用到在该表上执行的函数表达式上。
请为每一列使用与远程 ClickHouse 数据类型相对应的数据类型。支持的列选项如下:
  • column_name:ClickHouse 侧的列名。在反解析查询和 insert 时,会优先使用该名称,而不是 PostgreSQL attribute 名称。 这对于将未加引号的小写 PostgreSQL 列名映射到 区分大小写的 ClickHouse 列非常有用,例如:
  • AggregateFunction:应用于 [AggregateFunction 类型]列的 aggregate function 名称。将数据类型映射为传递给该函数的 ClickHouse 类型, 并通过相应的列选项指定 aggregate function 的名称,pg_clickhouse 会自动为计算该列的 aggregate function 追加 Merge
  • SimpleAggregateFunction:应用于 [SimpleAggregateFunction 类型]列的 aggregate function 名称。将数据类型映射为 传递给该函数的 ClickHouse 类型,并通过相应的 列选项指定 aggregate function 的名称。

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 表创建一个本地副本,并连接到该副本,而不是远程表:
在这种情况下,我们可以将更多聚合下推到 ClickHouse: 按 node_id 而不是本地列分组,然后稍后再与查找表连接:
“Foreign Scan”节点现在会将按 node_id 的聚合下推,从而将必须拉回 Postgres 的 行数从 1000 行 (全部 行) 减少到仅 8 行,每个节点一行。

PREPARE, EXECUTE, DEALLOCATE

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

INSERT

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

COPY

使用 COPY 命令将一批行插入远程 ClickHouse 表:
⚠️ Batch 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 settings。值中的空格、逗号和反斜杠需要用反斜杠转义:
或者使用单引号括起的值,以避免对空格和逗号进行转义;也可以考虑 使用[美元引号],这样就无需使用双引号了:
如果你注重可读性,并且需要设置许多参数,可以分成多 行,例如:
在某些情况下,如果某些设置会干扰 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 ROLERESET 命令重置 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 列 只用于二进制数据,切勿在两者之间来回切换。

函数与算子参考

函数

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

clickhouse_raw_query

通过其 HTTP 接口连接到 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 中对应函数的映射关系如下:

下推运算符

  • 数组切片 (arr[L:U]): arraySlice
  • @> (数组包含) : hasAll
  • <@ (数组包含于) : hasAll
  • && (数组有交集) : hasAny
  • ~ (正则表达式匹配) : match
  • !~ (正则表达式不匹配) : match
  • ~* (不区分大小写的正则表达式无匹配) : match
  • !~* (不区分大小写的正则表达式不匹配) : match
  • ->> (将 JSON/JSONB 中的元素提取为文本) : 子列语法
  • -> (提取 JSON/JSONB) : toJSONString + 子列语法

自定义函数

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

扩展下推

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

re2

所有 [re2 扩展] 函数都可 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 表达式作为 实参 传递。例如,以下 PostgreSQL 查询:
映射为以下 ClickHouse 查询:
请注意,非默认的 ORDER BY 后缀 DESC 和 `NULLS FIRST“ 不受支持,并会报错。

下推窗口函数

这些 PostgreSQL [窗口函数] 支持下推到 ClickHouse,并使用带 OVER (PARTITION BY ... ORDER BY ...) 子句的形式;在适用时,也包括窗口帧定义。 排名函数 (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 扩展];对于它,pg_clickhouse 支持将与 ClickHouse 兼容的 RE2 正则表达式直接下推

to_char()

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

已转换的关键字

引用文本和字面量

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

作者

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