PostgreSQL码农集散地

ClickHouse 为什么要抱紧 PG 大腿?

本期播客

ClickHouse 来抱 PG 大腿了

ClickHouse 给PG开发了一款插件: pg_clickhouse . PG 用户可以无缝使用 ClickHouse 的OLAP能力.

在开始介绍pg_clickhouse之前, 先思考一下:

从商业角度来看, 为什么 ClickHouse 要免费为 PostgreSQL 用户开发 pg_clickhouse 扩展(插件)呢?


🚀 商业驱动力分析:ClickHouse 开发 pg_clickhouse 的原因

ClickHouse 采取这一行动的核心目标是: 降低用户迁移的摩擦,扩大 ClickHouse 的市场占有率,并加速从 OLTP/混合数据库到专业 OLAP 数据库的过渡。

1. 捕捉最大的潜在用户群和降低迁移摩擦

这是最直接且最重要的原因。

  • 识别核心痛点:PostgreSQL 是主要的迁移来源
    • 根据文章开头提到的:“仅次于自托管的 ClickHouse,PostgreSQL 是最常见的迁移来源。” 这表明 PostgreSQL 用户在遇到分析性能瓶颈时,是转向 ClickHouse 的最大目标客户群。
  • 解决“代码重写”的痛点(摩擦)
    • 数据迁移(Data Migration)已经有 ClickPipes 这样的工具来简化。
    • 真正的瓶颈在于应用层:用户在 PostgreSQL 上积累了多年的分析 SQL、ORMs、仪表板(dashboards)和业务逻辑。重写这些代码是耗时且高风险的。
    • pg_clickhouse 允许用户“无需修改”或仅需少量修改(例如更改 search_path)即可运行现有的分析查询。这极大地降低了采用 ClickHouse 的技术门槛和时间成本。

2. 促进工作负载的分离和专业化

ClickHouse 是一家专注于 OLAP(联机分析处理)的数据库公司,其商业利益在于说服客户将分析工作负载转移到其高性能引擎上。

  • 加速 OLAP 领域的统治
    • 通过将分析查询透明地从 PostgreSQL 转移到 ClickHouse 执行,ClickHouse 成功地将自己插入到客户的数据架构中,成为其核心分析层。
    • 用户可以继续使用 PostgreSQL 处理 OLTP(联机事务处理)和少量混合查询,同时享受 ClickHouse 在大规模分析上的性能优势。
  • 定位为最佳“分析后端”
    • 该插件使 PostgreSQL 成为了一个分析代理(Analytics Proxy)。用户与熟悉的 Postgres 交互,但查询的繁重工作(查询下推 - Query Pushdown)被交给 ClickHouse 完成。这强化了 ClickHouse 作为高性能、不可或缺的分析后端的定位。

3. 展现技术实力和产品成熟度

一个功能强大的 FDW(外部数据封装器)不仅是一个集成工具,它还代表了 ClickHouse 的技术能力。

  • 解决深度分析的挑战
    • 文章重点提到了对聚合函数下推(Aggregate Function Pushdown)和半连接下推(SEMI JOIN Pushdown)的改进。这些功能是复杂分析查询(如 TPC-H 基准测试所示)的关键。
    • 如果插件只能处理简单的查询,那么它的商业价值有限。通过解决这些复杂的查询下推挑战,ClickHouse 向市场证明:它不仅能存储数据,还能在复杂的应用场景下,无缝、高效地接管你的分析工作负载。
  • 建立和控制生态系统
    • 接手并改进 clickhouse_fdw 的现有工作,并将其现代化,使 ClickHouse 能够控制和加速这一关键的集成点。确保其与最新的 PostgreSQL 和 ClickHouse 版本兼容、可靠,这对于商业推广至关重要。

4. 商业模式和未来营收

虽然这个插件本身是开源的,但其最终目的是驱动 ClickHouse Cloud 等商业服务的采用。

  • 驱动 ClickHouse Cloud 采用
    • 该插件使客户能够更轻松地试用和采用 ClickHouse Cloud 服务。一旦数据和查询逻辑转移到了 ClickHouse 生态中,客户更倾向于选择官方提供的、全托管、运维简单的 ClickHouse Cloud,从而转化为 ClickHouse 的付费用户。
  • 锁定客户和生态效应
    • 一旦客户通过 pg_clickhouse 将分析工作流程深度集成到 ClickHouse 中,转换到其他分析数据库的成本将再次变高,从而提高了客户的留存率(Customer Retention)和转换成本(Switching Costs)。

总结:一个双赢的战略

ClickHouse 开发 pg_clickhouse 是一个精明的商业战略:

视角
目标
商业价值
对用户
零(低)代码重写、查询加速
降低迁移风险和成本
,即时获得高性能分析。
对 ClickHouse
扩大用户群、抢占市场份额
加速客户获取
,将最大的潜在用户群(Postgres 用户)转化为 ClickHouse 用户。
技术/架构
工作负载分离和专业化
巩固 ClickHouse 作为专业高性能 OLAP 引擎的地位。

以下内容翻译自:  https://clickhouse.com/blog/introducing-pg_clickhouse

pg_clickhouse 介绍

在过去一年里,我们注意到已将分析工作负载迁移到 ClickHouse Cloud 的客户中存在一个显著的模式:仅次于自托管的 ClickHouse,PostgreSQL 是最常见的迁移来源。ClickPipes 使这些用例中的数据复制和迁移变得容易。然而,我们发现用户在将查询和应用程序代码从 PostgreSQL 迁移到 ClickHouse 时,仍然面临着巨大的挑战。为了解决这个问题,几个月前我们开始研究如何简化和缩短将分析查询从 PostgreSQL 迁移到 ClickHouse 所需的时间。

今天,我们很高兴发布 pg_clickhouse v0.1.0,这是一个采用 Apache 2 许可的 PostgreSQL 扩展 (extension),它允许直接从 PostgreSQL 透明地在 ClickHouse 上执行分析查询。

请从以下位置下载 pg_clickhouse:
PGXN GitHub

或者通过启动 Docker 实例来试用:

docker run --name pg_clickhouse -e POSTGRES_PASSWORD=my_pass   
       -d ghcr.io/clickhouse/pg_clickhouse:18  

建议从教程开始。

目标

考虑一个常见情况:某个组织构建了一个由 Postgres 支持的应用程序,其中不仅包含业务数据和事务处理,还包括日志和指标。随着产品的发展,用户流量和数据量呈指数级增长。因此,为面向客户的实时功能和可观测性系统提供支持的分析查询开始变慢。

开发人员通常会通过使用 PostgreSQL 只读副本 (read replicas) 来缓解这些问题,但这充其量只是一个临时解决方案。最终,他们会考虑将工作负载转移到像 ClickHouse 这样的专业分析数据库。ClickPipes 为快速数据迁移提供了动力,但对于针对这些数据的现有 PostgreSQL 查询(通常由 SQL 库或 ORMs 创建)该怎么办呢?

耗时的部分不是移动数据;ClickPipes 已经解决了这个问题。耗时的是重写嵌入在仪表板 (dashboards)、ORMs 和 cron jobs 中数月或数年的分析 SQL。

我们设想了一个 PostgreSQL 扩展 (extension),它可以减少迁移这些查询的需要,用户只需将这些查询指向新的 Postgres 数据库或模式 (schema),即可在数据迁移后进行工作负载迁移。

因此,我们着手构建 pg_clickhouse,并牢记以下目标:

  • 提供从 PostgreSQL 执行 ClickHouse 查询的能力
  • 允许现有的 PostgreSQL 查询无需修改即可运行
  • 将查询执行下推 (Query Pushdown) 到 ClickHouse
  • 为查询和查询下推 (Query Pushdown) 的持续发展奠定基础

如果 ClickHouse 表看起来就像常规的 PostgreSQL 表一样会怎样?假设它们存在于一个与现有 Postgres 分析表分离的模式 (schema) 中,但提供了相同的结构?这种模式将允许现有查询像以前一样工作,只需更改 search_path 即可。

历史

SQL/MED 正是通过提供数据库扩展(称为外部数据封装器 (Foreign Data Wrapper 或 FDW))来解决这种用例的,它允许通过 SQL 管理外部数据。PostgreSQL 自 2011 年的 9.3 版本开始就支持外部数据封装器 (FDW),此后,一系列功能强大的“FDW”扩展 (extensions)(它们的常用叫法)不断发展壮大。

我们四处寻找现有解决方案,并很快找到了 clickhouse_fdw 并进行了验证,它由 Ildus Kurbangaliev 为 Adjust 开发,基于 Ibrar Ahmed 在 Percona 的初步工作。它不仅支持原始数据访问,还支持查询下推 (Query Pushdown),包括对某些 JOIN 和聚合函数 (Aggregate Function) 的支持。

该项目起源于 2019 年,是从 PostgreSQL FDW 的规范参考实现 postgres_fdw 的一个分支,以及 ClickHouse C++ 库的一个分支派生而来。遗憾的是,自 2020 年底以来,它只进行了基础维护工作,大多是确保其能与新版本 PostgreSQL 配合使用的补丁。clickhouse_fdw 是一个很好的开端,但它没有受益于 PostgreSQL FDW API 中最新的查询下推 (Pushdown) 改进,包括对高级聚合、半连接 (SEMI JOIN)、子查询 (subqueries) 等的支持。它也缺乏对 Linux 以外平台的测试和支持,并且在新版 PostgreSQL 发布时更新滞后。在与 Ildus 交流后,我们将大部分功能导入了一个新项目 pg_clickhouse,并保留了 Apache 2 许可,以保持分发的一致性。

改进

尽管 clickhouse_fdw 及其前身 postgres_fdw 为我们的 FDW 奠定了基础,但我们着手对代码和构建过程进行现代化,修复错误并解决不足,并将其打造成为一个完整的产品,其特点是分析查询和聚合几乎可以实现通用下推 (Pushdown)。

这些进步包括:

  • 为 PostgreSQL 扩展采用标准的 PGXS 构建流程
  • 添加预处理 INSERT 支持,并采用最新的 ClickHouse C++ 库版本
  • 创建测试用例和 CI 工作流 (CI workflows),以确保它能在 PostgreSQL 13-18 版本和 ClickHouse 22-25 版本上运行
  • 支持 TLS 连接 (TLS-based connections),适用于二进制协议和 HTTP API,这是 ClickHouse Cloud 所必需的
  • 支持 Bool、Decimal 和 JSON 类型
  • 透明的聚合函数下推 (Aggregate Function Pushdown),包括对有序集聚合 (ordered-set aggregates) 的支持,例如 percentile_cont()
  • 半连接下推 (SEMI JOIN Pushdown)

最后这两项功能显著提升了外部数据封装器 (Foreign Data Wrapper) 对分析数据库的适用性。毕竟,全部意义在于受益于在专业且高效的引擎上运行分析工作负载的执行速度。如果它只是返回数百万行数据让 PostgreSQL 来聚合,那将没有太大用处。

聚合函数下推 (Aggregate Function Pushdown)

有序集聚合 (Ordered-set aggregates) 是最难在不同引擎之间映射的函数之一,因为它们的语法不能直接转换。理想情况下,一个聚合函数 (Aggregate Function) 会完全下推 (Pushdown) 到 ClickHouse 以实现高效执行。考虑一下这个改编自我们 HouseClick 项目的查询:

SELECT
type,  
round(min(price)) + 100ASmin,  
round(max(price)) ASmax,  
round(percentile_cont(0.5) WITHINGROUP (ORDERBY price)) ASmedian,  
round(percentile_cont(0.25) WITHINGROUP (ORDERBY price)) AS"25th",  
round(percentile_cont(0.75) WITHINGROUP (ORDERBY price)) AS"75th"
FROM
    uk.uk_price_paid  
GROUPBY
type

该查询使用了 3 个聚合函数 (Aggregate Function)。min() 和 max() 会自动下推 (Pushdown),因为它们在 ClickHouse 和 PostgreSQL 中具有相同的名称。但 percentile_cont() 则不会,它计算或平均了所有值中某个百分比内的最高值。ClickHouse 中没有这样的函数;ClickHouse 也不支持 WITHIN GROUP (ORDER BY x) 这种有序集聚合 (ordered set aggregate) 语法。

然而,它确实提供了参数化聚合函数 (parametric aggregate functions),包括 quantile,它实现了一部分有序集聚合 (ordered set aggregate) 语法。因此,pg_clickhouse 将此查询重写为 ClickHouse 格式:

SELECT
type,  
    (round(min(price)) + 100),  
round(max(price)),  
round(quantile(0.5)(price)),  
round(quantile(0.25)(price)),  
round(quantile(0.75)(price))  
FROM
    uk.uk_price_paid  
GROUPBY
type

请注意 percentile_cont() 的直接参数 (0.5、0.25、0.75) 到 quantile() 的参数化常量的透明转换,以及 ORDER BY 参数到函数参数的转换:

percentile_cont(0.5) WITHIN GROUP (ORDER BY price) => quantile(0.5)(price)

更重要的是,pg_clickhouse,就像它之前的 clickhouse_fdw 一样,将 PostgreSQL 聚合 FILTER (WHERE) 表达式转换为 ClickHouse 的 -If 组合器 (combinators)。这是来自 HouseClick 的完整 PostgreSQL 查询:

SELECT
type,  
round(min(price)) + 100ASmin,  
round(min(price) FILTER (WHERE town='ILMINSTER'AND district='SOUTH SOMERSET'AND postcode1='TA19')) AS min_filtered,  
round(max(price)) ASmax,  
round(max(price) FILTER (WHERE town='ILMINSTER'AND district='SOUTH SOMERSET'AND postcode1='TA19')) AS max_filtered,  
round(percentile_cont(0.5) WITHINGROUP (ORDERBY price)) ASmedian,  
round(percentile_cont(0.5) WITHINGROUP (ORDERBY price) FILTER (WHERE town='ILMINSTER'AND district='SOUTH SOMERSET'AND postcode1='TA19')) AS median_filtered,  
round(percentile_cont(0.25) WITHINGROUP (ORDERBY price)) AS"25th",  
round(percentile_cont(0.25) WITHINGROUP (ORDERBY price) FILTER (WHERE town='ILMINSTER'AND district='SOUTH SOMERSET'AND postcode1='TA19')) AS"25th_filtered",  
round(percentile_cont(0.75) WITHINGROUP (ORDERBY price)) AS"75th",  
round(percentile_cont(0.75) WITHINGROUP (ORDERBY price) FILTER (WHERE town='ILMINSTER'AND district='SOUTH SOMERSET'AND postcode1='TA19')) AS"75th_filtered"
FROM
    uk.uk_price_paid  
GROUPBY
type

使用 EXPLAIN 运行它,查看查询计划:

                    QUERY PLAN                       
---------------------------------------------------  
 Foreign Scan  (cost=1.00..-0.90 rows=1 width=112)  
   Relations: Aggregate on (uk_price_paid)  

Fully pushed down!(完全下推!)这种重写避免了将数百万行数据传回 PostgreSQL,并将繁重的工作保留在 ClickHouse 内部。使用 EXPLAIN (VERBOSE) 也会输出发送到 ClickHouse 的查询(此处已重新格式化):

SELECT
type,  
    (round(min(price)) + 100),  
round(minIf(price,((((town = 'ILMINSTER') AND (district = 'SOUTH SOMERSET') AND (postcode1 = 'TA19'))) > 0))),  
round(max(price)),  
round(maxIf(price,((((town = 'ILMINSTER') AND (district = 'SOUTH SOMERSET') AND (postcode1 = 'TA19'))) > 0))),  
round(quantile(0.5)(price)),  
round(quantileIf(0.5)(price,((((town = 'ILMINSTER') AND (district = 'SOUTH SOMERSET') AND (postcode1 = 'TA19'))) > 0))),  
round(quantile(0.25)(price)),  
round(quantileIf(0.25)(price,((((town = 'ILMINSTER') AND (district = 'SOUTH SOMERSET') AND (postcode1 = 'TA19'))) > 0))),  
round(quantile(0.75)(price)),  
round(quantileIf(0.75)(price,((((town = 'ILMINSTER') AND (district = 'SOUTH SOMERSET') AND (postcode1 = 'TA19'))) > 0)))   
FROM
    uk.uk_price_paid  
GROUPBY
type
;  

请注意,每个 FILTER (WHERE) 表达式都已转换为带有 -If 后缀的 ClickHouse 函数,用于计算等效的过滤。换句话说,这个表达式:

min(price) FILTER (WHERE town='ILMINSTER' AND district='SOUTH SOMERSET' AND postcode1='TA19')  

变成了:

minIf(price,((((town = 'ILMINSTER') AND (district = 'SOUTH SOMERSET') AND (postcode1 = 'TA19'))) > 0))  

半连接下推 (SEMI JOIN Pushdown)

在我们确定了 pg_clickhouse 的基础功能后,我们开始针对 TPC-H(这个受人尊敬的“决策支持工作负载”数据库基准测试)进行下推 (Pushdown) 测试,TPC-H 数据以缩放因子 1 加载到 ClickHouse 中。最初,在添加了对 Decimal 类型的支持后,22 个查询中有 10 个运行很快;在这些查询中,只有 3 个从 pg_clickhouse 外部表 (foreign tables) 完全下推到 ClickHouse 源。其中之一是查询 3 的连接:

EXPLAIN (ANALYZE, COSTS)  
-- using default substitutions  
select
    l_orderkey,  
sum(l_extendedprice * (1 - l_discount)) as revenue,  
    o_orderdate,  
    o_shippriority  
from
    customer,  
    orders,  
    lineitem  
where
    c_mktsegment = 'BUILDING'
and c_custkey = o_custkey  
and l_orderkey = o_orderkey  
and o_orderdate < date'1995-03-15'
and l_shipdate > date'1995-03-15'
groupby
    l_orderkey,  
    o_orderdate,  
    o_shippriority  
orderby
    revenue desc,  
    o_orderdate  
LIMIT10;  
                                            QUERY PLAN                                               
---------------------------------------------------------------------------------------------------  
 Foreign Scan  (cost=0.00..-10.00 rows=1 width=44) (actual time=60.146..60.162 rows=10.00 loops=1)  
   Relations: Aggregate on (((customer) INNER JOIN (orders)) INNER JOIN (lineitem))  
   FDW Time: 0.106 ms  
 Planning:  
   Buffers: shared hit=230  
 Planning Time: 6.973 ms  
 Execution Time: 61.567 ms  
(7 rows)  

然而,许多失败的其余查询使用了连接 (JOIN) 到子查询 (subqueries) 或 WHERE 子句中的 EXISTS 子查询 (EXISTS subqueries)。查询 4 是后一种情况的完美示例(禁用了 ANALYZE,因为它耗时太久):

EXPLAIN (COSTS, VERBOSE, BUFFERS)  
-- using default substitutions  
select
    o_orderpriority,  
count(*) as order_count  
from
    orders  
where
    o_orderdate >= date'1993-07-01'and o_orderdate < date(date'1993-07-01' + interval'3month')  
andexists (select * from lineitem where l_orderkey = o_orderkey and l_commitdate < l_receiptdate)  
groupby
    o_orderpriority  
orderby
    o_orderpriority;  
                                                                                                                                                                                          QUERY PLAN                                                                                                                                                                                            
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
 Sort  (cost=-80.86..-80.36 rows=200 width=40)  
   Output: orders.o_orderpriority, (count(*))  
   Sort Key: orders.o_orderpriority  
   ->  HashAggregate  (cost=-90.50..-88.50 rows=200 width=40)  
         Output: orders.o_orderpriority, count(*)  
         Group Key: orders.o_orderpriority  
         ->  Nested Loop  (cost=3.50..-93.00 rows=500 width=32)  
               Output: orders.o_orderpriority  
               Join Filter: (orders.o_orderkey = lineitem.l_orderkey)  
               ->  HashAggregate  (cost=2.50..4.50 rows=200 width=4)  
                     Output: lineitem.l_orderkey  
                     Group Key: lineitem.l_orderkey  
                     ->  Foreign Scan on tpch.lineitem  (cost=0.00..0.00 rows=0 width=4)  
                           Output: lineitem.l_orderkey, lineitem.l_partkey, lineitem.l_suppkey, lineitem.l_linenumber, lineitem.l_quantity, lineitem.l_extendedprice, lineitem.l_discount, lineitem.l_tax, lineitem.l_returnflag, lineitem.l_linestatus, lineitem.l_shipdate, lineitem.l_commitdate, lineitem.l_receiptdate, lineitem.l_shipinstruct, lineitem.l_shipmode, lineitem.l_comment  
                           Remote SQL: SELECT l_orderkey FROM tpch.lineitem WHERE ((l_commitdate < l_receiptdate))  
               ->  ForeignScanon tpch.orders  (cost=1.00..-0.50rows=1 width=36)  
Output: orders.o_orderkey, orders.o_custkey, orders.o_orderstatus, orders.o_totalprice, orders.o_orderdate, orders.o_orderpriority, orders.o_clerk, orders.o_shippriority, orders.o_comment  
                     Remote SQL: SELECT o_orderkey, o_orderpriority FROM tpch.orders WHERE ((o_orderdate >= '1993-07-01')) AND ((o_orderdate < '1993-10-01')) ORDERBY o_orderpriority ASCNULLSLAST
 Planning:  
   Buffers: shared hit=236
(20rows)  

查询计划中深层的两次外部扫描 (foreign scans) 对于如此简单的查询来说,永远不会是高效的!

我们已经开始通过两种方式解决这些情况:

  • 设置成本 (costs) 以鼓励 PostgreSQL 规划器 (planner) 下推 (Pushdown) 查询,以适应分析用例
  • 更重要的是,我们增加了对半连接下推 (SEMI JOIN Pushdown) 的支持

这些更改为 22 个查询中的 21 个带来了高效执行(不到 1 秒),并为 12 个查询实现了完全下推 (Pushdown),包括查询 4:

EXPLAIN (ANALYZE, COSTS, VERBOSE, BUFFERS)  
-- using default substitutions  
select
    o_orderpriority,  
count(*) as order_count  
from
    orders  
where
    o_orderdate >= date'1993-07-01'and o_orderdate < date(date'1993-07-01' + interval'3month')  
andexists (select * from lineitem where l_orderkey = o_orderkey and l_commitdate < l_receiptdate)  
groupby
    o_orderpriority  
orderby
    o_orderpriority;  
                                                                                                                                                             QUERY PLAN                                                                                                                                                                
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------  
 Foreign Scan  (cost=1.00..5.10 rows=1000 width=40) (actual time=51.835..51.847 rows=5.00 loops=1)  
   Output: orders.o_orderpriority, (count(*))  
   Relations: Aggregate on ((orders) LEFT SEMI JOIN (lineitem))  
   Remote SQL: SELECT r1.o_orderpriority, count(*) FROM  tpch.orders r1 LEFTSEMIJOIN tpch.lineitem r3 ON (((r3.l_commitdate < r3.l_receiptdate)) AND ((r1.o_orderkey = r3.l_orderkey))) WHERE ((r1.o_orderdate >= '1993-07-01')) AND ((r1.o_orderdate < '1993-10-01')) GROUPBY r1.o_orderpriority ORDERBY r1.o_orderpriority ASC
   FDW Time: 0.056 ms  
 Planning:  
   Buffers: shared hit=242
 Planning Time: 6.583 ms  
 Execution Time: 54.937 ms  
(9rows)  

下表比较了常规 PostgreSQL 表、引入 SEMI JOIN 性能之前的 pg_clickhouse 以及具有 SEMI JOIN 性能的 pg_clickhouse(即今天发布的版本)之间的查询性能。测试针对加载了缩放因子为 1 的 TPC-H 数据的 PostgreSQL 和 ClickHouse 表运行;✅ 表示完全下推 (Full Pushdown),而短横线表示查询在 1 分钟后被取消:

查询 (Query)
Postgres 运行时 (Runtime)
原始运行时 (Original Runtime)
SEMI JOIN
 运行时 (Runtime)
1
4478ms
✅ 82ms
✅ 73ms
2
560ms
-
-
3
1454ms
✅ 74ms
✅ 74ms
4
650ms
-
✅ 67ms
5
452ms
-
✅ 104ms
6
740ms
✅ 33ms
✅ 42ms
7
633ms
-
✅ 83ms
8
320ms
-
✅ 114ms
9
3028ms
-
✅136ms
10
6ms
10ms
✅ 10ms
11
213ms
-
✅ 78ms
12
1101ms
99ms
✅ 37ms
13
967ms
1028ms
1242ms
14
193ms
168ms
✅ 51ms
15
1095ms
101ms
522 ms
16
492ms
1387ms
1639ms
17
1802ms
-
9ms
18
6185ms
-
10ms
19
64ms
75m
65ms
20
473ms
-
4595ms
21
1334ms
-
1702ms
22
257ms
-
268ms

请注意,对于支持 SEMI JOIN 的 pg_clickhouse 外部表 (foreign tables) 而言,几乎所有查询的整体性能都有所提升;在少数情况下(查询 13、15 和 16),查询优化器 (query optimizer) 选择了较慢的计划,我们显然需要彻底查明查询 2 的性能问题。但其他查询的总体性能提升是不可否认的。

未来

我们对这些改进感到非常高兴,并很高兴能在首个版本中将它们带给您。但我们还远远没有完成。我们的首要重点是在添加 DML (数据操作语言) 功能之前,完成对分析工作负载的下推覆盖 (Pushdown coverage)。我们的路线图 (road map):

  • 优化剩余 10 个未下推 (Pushdown) 的 TPC-H 查询计划
  • 测试并修复 ClickBench 查询的下推 (Pushdown) 问题
  • 支持所有 PostgreSQL 聚合函数 (Aggregate Function) 的透明下推 (Pushdown)
  • 支持所有 PostgreSQL 函数的透明下推 (Pushdown)
  • 实现全面的子查询下推 (Subquery Pushdown)
  • 通过 CREATE SERVER 和 CREATE USER 允许设置服务器级别和用户级别的 ClickHouse 配置
  • 支持所有 ClickHouse 数据类型 (data types)
  • 支持轻量级的 DELETE 和 UPDATE 操作
  • 通过 COPY 支持批量插入 (batch insertion)
  • 添加一个函数来执行任意的 ClickHouse 查询 (query) 并将其结果作为表 (tables) 返回
  • 当所有 UNION 查询都针对远程数据库时,添加对 UNION 查询下推 (Pushdown) 的支持