pg_clickhouse 0.3.0:把查询推下去,把性能留下来

2026-05-12 39 预计阅读时间:1 分钟
来源:postgr.es AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:8 分钟

pg_clickhouse 这个扩展的核心哲学只有三个词:pushdown、pushdown、pushdown。把计算推到 ClickHouse 那边执行,Postgres 只负责接收结果——这才是跨库查询该有的样子。v0.3.0 把这套哲学推得更深了:JSON 类型映射补齐、正则表达式行为统一、格式化函数下推,还顺手修了一个 SSRF 漏洞。

JSON 类型映射终于对齐了

之前 HTTP 驱动已经支持把 ClickHouse 的 JSON 类型映射到 PostgreSQL 的 JSONB,但二进制驱动一直缺这块。v0.3.0 补上了——现在两种驱动都能正确处理 ClickHouse JSON → Postgres JSONB 的映射。

反过来也支持了:Postgres 的 json 类型可以映射到 ClickHouse 的 json 类型。不过实际使用中,jsonb 更贴近 ClickHouse JSON 的语义(两者都保留键顺序、都支持嵌套查询),所以除非你有特殊理由,优先用 jsonb

函数下推:从格式化到正则再到模糊匹配

to_char → formatDateTime

Postgres 的 to_char(timestamp, fmt) 现在能下推到 ClickHouse 的 formatDateTime()。支持的格式符号包括:YYYYMMDDDDDHH24HH12HHMISSQMonDyAM/PM 及小写变体。只有二进制兼容的格式才会下推,不兼容的仍由 Postgres 本地计算。

正则表达式:用 re2 扩展消除行为差异

这是个容易被忽视但实际很坑的问题:Postgres 用 POSIX 正则,ClickHouse 用 RE2 正则,语法和行为有差异。同一条正则表达式在两边可能给出不同结果。

v0.3.0 的解决方案是下推新的 re2 扩展里的函数。这个扩展在 Postgres 里提供 RE2 风格的正则函数,下推到 ClickHouse 后行为完全一致。Docker 镜像现在已经包含 re2 扩展,开箱即用。

模糊匹配与数组函数

soundex()levenshtein()(来自 fuzzystrmatch 扩展)现在也能下推。intarray 扩展的 idx 函数下推则做了文档补录。加上之前版本已有的 array_cat()array_to_string() 等数组函数下推,跨库查询时能留在 ClickHouse 执行的函数越来越多了。

文本函数的 UTF-8 修正

length(text)strpos(text, text) 的下推目标从 ClickHouse 的 length/position 改成了 lengthUTF8/positionUTF8。如果你存的是多字节字符(中文、日文等),这个修正很重要——否则按字节计数和按字符计数会给出不同结果。

列名映射与安全修复

column_name 选项

CREATE FOREIGN TABLE 现在支持 column_name 选项,让 Postgres 列名和 ClickHouse 列名可以不同。二进制驱动的集成也修好了。

-- Postgres 端列名叫 user_name,ClickHouse 端叫 username
CREATE FOREIGN TABLE clickhouse_users (
    id        bigint,
    user_name text OPTIONS (column_name 'username'),
    created_at timestamptz
) SERVER clickhouse_server
OPTIONS (table 'users');

SSRF 漏洞修复

clickhouse_raw_query() 函数之前对 public 开放了 EXECUTE 权限,存在 SSRF 风险。v0.3.0 移除了这个权限。这也是版本号跳到 0.3 的原因——需要手动升级:

ALTER EXTENSION pg_clickhouse UPDATE TO '0.3';

一个实际的下推查询示例

下面演示如何在 Postgres 中通过 pg_clickhouse 查询 ClickHouse,并利用下推获得更好的性能。假设你已经在 ClickHouse 有一张事件表。

安装与基础配置

-- 1. 安装扩展
CREATE EXTENSION pg_clickhouse;

-- 2. 配置 ClickHouse 外部服务器
CREATE SERVER clickhouse_server
FOREIGN DATA WRAPPER pg_clickhouse
OPTIONS (
    host 'clickhouse.example.com',
    port '8123',          -- HTTP 端口;二进制驱动用 9000
    driver 'http',        -- 或 'binary'
    database 'analytics'
);

-- 3. 创建外部表,利用 column_name 映射和 JSONB 类型
CREATE FOREIGN TABLE ch_events (
    event_id    bigint,
    event_time  timestamptz,
    event_type  text,
    payload     jsonb,               -- 映射 ClickHouse JSON 类型
    region      text OPTIONS (column_name 'geo_region')
) SERVER clickhouse_server
OPTIONS (table 'events');

利用下推的查询

-- to_char 下推:按季度聚合,计算在 ClickHouse 完成
SELECT to_char(event_time, 'Q') AS quarter,
       count(*) AS event_count
FROM ch_events
WHERE event_time >= '2024-01-01'
GROUP BY quarter
ORDER BY quarter;

-- JSONB 访问器下推:直接在 ClickHouse 解析 JSON
SELECT event_type,
       payload->>'action' AS action,
       count(*) AS cnt
FROM ch_events
WHERE payload->>'action' IS NOT NULL
GROUP BY event_type, action;

-- re2 正则下推:行为与 ClickHouse 一致
-- 需先安装 re2 扩展:CREATE EXTENSION re2;
SELECT re2_matches(event_type, '^click_.*') AS is_click_event,
       count(*)
FROM ch_events
GROUP BY is_click_event;

这些查询中的函数和过滤条件会被推到 ClickHouse 执行,Postgres 只拿到聚合后的少量结果行,网络传输和本地计算都大幅减少。

HTTP 流式传输的内存改进

之前版本的文章还展示了 HTTP 结果集流式传输的改进。老版本会把整个结果集加载到内存再解析,新版本的 HTTP 驱动改为流式处理,内存占用大幅下降。对于返回大量行的查询,这个改进尤其明显。

下推行为的收紧

v0.3.0 还做了一件容易被忽略的事:移除了从 postgres_fdw 继承的"自动下推内置函数"行为。以前,只要 Postgres 和 ClickHouse 有同名函数,就可能被自动下推——但同名不代表语义相同,这会引发静默的错误结果。

现在所有可下推的内置函数都必须显式映射。这意味着下推更安全了,但也意味着某些之前"碰巧"能下推的函数现在不会了。如果你发现查询变慢,检查一下是否撞上了这个变化。

升级检查清单

  • 必须执行ALTER EXTENSION pg_clickhouse UPDATE TO '0.3';(修复 SSRF)
  • 检查依赖:如果用了自动下推的内置函数,确认它们是否还在显式映射列表中
  • 二进制驱动用户:JSON 类型映射现在可用,考虑把 text 列改为 jsonb 以获得更好的查询能力
  • 正则用户:安装 re2 扩展,统一 Postgres 和 ClickHouse 的正则行为
  • 多字节文本用户length()strpos() 下推目标已改为 UTF-8 版本,验证结果是否符合预期

pg_clickhouse 的方向很清晰——能推下去的都推下去,推不了的就补映射、修语义差异。0.3.0 在 JSON、正则、格式化这几个高频场景上补了关键短板,SSRF 修复则让生产部署更安心。如果你在用 Postgres 做"统一入口"而把分析数据留在 ClickHouse,这个版本值得立刻升级。


相关推荐