全部产品
Search
文档中心

云数据库 RDS:如何使用DuckDB加速查询?

更新时间:Jun 11, 2026

RDS PostgreSQL 通过 rds_duckdb 插件将分析型 SELECT 查询自动转发至 DuckDB 列存引擎执行,显著加快复杂查询的响应速度,且无需修改业务 SQL。本文介绍在已完成插件创建和 DuckDB 表创建的前提下,如何将查询转发到 DuckDB 执行,以及相关进阶功能与排查方法。

您可以加入RDS PostgreSQL插件交流钉钉群(103525002795),进行咨询、交流和反馈,获取更多关于插件的信息

前提条件

使用本功能前,请确认实例满足以下条件:

  • 主实例大版本为 RDS PostgreSQL 13~18,且小版本为 20260130 及以上。如需在只读实例上加速,只读实例大版本需为 16~18,小版本同样为 20260130 及以上。

  • 使用分区表同步自动创建 DuckDB 表功能时,小版本需为 20260330 及以上。

  • 已完成 rds_duckdb 插件创建。

注意事项

  • rds_duckdb 目前仅加速 SELECT 类型的只读查询。DML(INSERT/UPDATE/DELETE)、DDL 以及包含未创建 DuckDB 表的查询,默认会回退到 PostgreSQL 执行。

  • Hint 仅支持设置 rds_duckdb.execution,不支持其他参数。

  • 通过 DMS 连接时,由于 DMS 会改写 SQL,建议使用 Hint 方式开启加速。

  • 简单查询(点查、小范围扫描)走 DuckDB 反而可能更慢,因为存在转发与启动开销。建议结合 rds_duckdb.plan_cost_threshold 过滤低成本查询,详情请参见 4.5 执行成本阈值

操作步骤

完整的查询加速操作分为三步:开启加速 → 验证转发效果 → 查看执行日志。

步骤一:开启DuckDB加速

您可以通过以下两种方式将 SELECT 查询转发到 DuckDB 执行。

  1. 方式一:使用 Hint(语句级)

    在 SELECT 语句前添加 Hint,仅对该条语句生效,适合临时验证或在单条慢查询上启用加速:

    /*+ set(rds_duckdb.execution on) */ SELECT * FROM my_table WHERE id = 1;
  2. 方式二:设置会话级参数

    在当前会话中执行如下命令,该会话内所有符合条件的查询都会被下推至 DuckDB:

    SET rds_duckdb.execution = on;

步骤二:验证转发效果(EXPLAIN / EXPLAIN ANALYZE)

通过执行计划可直观判断 SQL 是否被转发到 DuckDB 执行。

  1. 示例 1:单表查询被转发到 DuckDB

    /*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM test_hint;

    预期计划中出现 Custom Scan (DuckDBScan)DuckDB Execution Plan

                             QUERY PLAN
    ------------------------------------------------------------
     Custom Scan (DuckDBScan)  (cost=0.00..0.00 rows=0 width=0)
       DuckDB Execution Plan:
    
     ┌───────────────────────────┐
     │         SEQ_SCAN          │
     │    ────────────────────   │
     │      Table: test_hint     │
     │   Type: Sequential Scan   │
     │       Projections: a      │
     │                           │
     │          ~0 Rows          │
     └───────────────────────────┘
  2. 示例 2:关闭转发后恢复为原生 PostgreSQL 计划

    /*+ set(rds_duckdb.execution off) */ EXPLAIN SELECT * FROM test_hint;

    预期计划:

          QUERY PLAN
    -----------------------
     Seq Scan on test_hint
    (1 row)

步骤三:查看 DuckDB 日志(可选)

通过参数 rds_duckdb.enable_log_warning 控制 WARNING 级别提示是否输出到客户端,便于在查询未走 DuckDB 时定位原因。

  1. 开启 WARNING 输出(会话级即时生效):

    SET rds_duckdb.enable_log_warning = on;
  2. 观察客户端输出。当 enable_log_warning = on 时,以下场景会输出 WARNING

    • SQL 回退到 PG:Fallback postgres due to ...

    • 写操作不支持:Modification operations on DuckDB tables are currently not supported, fallback to PG.

    • 语句无需 DuckDB 执行:Statements don't need to be handed over to DuckDB, fallback to PG.

enable_log_warning = off(默认)时,上述信息以 DEBUG1 级别写入日志,不会出现在客户端。

进阶功能

以下功能用于优化加速效果或扩展同步范围,可根据业务需要选择性启用。

4.1 DDL 自动同步

RDS PostgreSQL 端的表结构变更(DDL)支持自动同步到 DuckDB,由以下参数控制:

参数

说明

默认值

rds_duckdb.enable_ddl_replication

是否开启 DDL 同步。

on

rds_duckdb.ddl_replication_fail_action

同步失败后的行为:refresh(自动全量刷新)、conflict(标记冲突并停止同步)、noop(不处理)。

refresh

已验证支持的 DDL 类型:

-- 增加列
ALTER TABLE tbl ADD COLUMN extra_1 int;
-- 删除列
ALTER TABLE tbl DROP COLUMN extra_1;
-- 增加带默认值的列
ALTER TABLE tbl ADD COLUMN extra_1 int DEFAULT 0;
-- 删除默认值
ALTER TABLE tbl ALTER COLUMN extra_1 DROP DEFAULT;
-- 修改列类型
ALTER TABLE tbl ALTER COLUMN extra_1 TYPE varchar;
-- 重命名列
ALTER TABLE tbl RENAME COLUMN extra_1 TO extra_2;
-- 重命名表
ALTER TABLE tbl RENAME TO tbl_new;
-- 事务内 DDL
BEGIN;
ALTER TABLE tbl ADD COLUMN extra_3 int;
INSERT INTO tbl VALUES (..., 1);
COMMIT;
-- Savepoint 回滚 DDL
BEGIN;
SAVEPOINT s1;
ALTER TABLE tbl DROP COLUMN extra_1;
ROLLBACK TO SAVEPOINT s1;
COMMIT;

不支持的 DDL 触发 fallback 示例:

-- 修改表 Schema(会触发自动全量刷新或冲突,取决于 fail_action)
ALTER TABLE tbl SET SCHEMA nsp1;

-- 删除主键(会导致同步中断,查询回退到 PG)
ALTER TABLE tbl DROP CONSTRAINT tbl_pkey;

删除主键后,duckdb_sync_stat 中该表将变为 not syncing 状态,查询不再走 DuckDB,直到主键或 REPLICA IDENTITY 恢复,并手动重刷该表。

4.2 分区表同步

说明

仅20260330 及以上版本支持。

rds_duckdb 支持将 PostgreSQL 分区表(单级与多级分区)同步到 DuckDB。

同步 PostgreSQL 分区表:需要将根分区及所有叶子分区均创建为 DuckDB 表。以单级分区表为例:

-- 创建 PG 分区表
CREATE TABLE test_partition (
    id int,
    age int,
    primary key (id, age)
) PARTITION BY RANGE (age);

CREATE TABLE test_partition_a PARTITION OF test_partition FOR VALUES FROM (0) TO (18);
CREATE TABLE test_partition_b PARTITION OF test_partition FOR VALUES FROM (18) TO (30);
CREATE TABLE test_partition_c PARTITION OF test_partition FOR VALUES FROM (30) TO (60);

INSERT INTO test_partition SELECT i, i FROM generate_series(0, 59) i;

-- 将根分区及所有叶子分区同步到 DuckDB
SELECT rds_duckdb.create_duckdb_tables('{test_partition, test_partition_a, test_partition_b, test_partition_c}');

查询根分区表示例:

/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM test_partition WHERE age >= 10 AND age < 20;

预期计划(裁剪后仅扫描命中分区):

 Custom Scan (DuckDBScan)  (cost=0.00..0.00 rows=0 width=0)
   DuckDB Execution Plan:

 ┌───────────────────────────┐
 │           UNION           ├──────────────┐
 └─────────────┬─────────────┘              │
 ┌─────────────┴─────────────┐┌─────────────┴─────────────┐
 │         SEQ_SCAN          ││         SEQ_SCAN          │
 │           Table:          ││           Table:          │
 │      test_partition_a     ││      test_partition_b     │
 │   Type: Sequential Scan   ││   Type: Sequential Scan   │
 │       Projections:        ││       Projections:        │
 │          Filters:         ││          Filters:         │
 │     age>=10 AND age<20││     age>=10 AND age<20│
 └───────────────────────────┘└───────────────────────────┘

同时支持多级分区表,示例如下:

CREATE TABLE test_multi_partition (
    id serial,
    sale_id int NOT NULL,
    sale_date date NOT NULL,
    amount numeric(15,2) NOT NULL,
    primary key(sale_id, sale_date)
) PARTITION BY RANGE (sale_date);

CREATE TABLE test_multi_partition_a_l1 PARTITION OF test_multi_partition
    FOR VALUES FROM ('2024-1-1') TO ('2025-1-1') PARTITION BY RANGE (sale_date);
CREATE TABLE test_multi_partition_b_l1 PARTITION OF test_multi_partition
    FOR VALUES FROM ('2025-1-1') TO ('2026-1-1') PARTITION BY RANGE (sale_date);

CREATE TABLE test_multi_partition_a_l2_1 PARTITION OF test_multi_partition_a_l1
    FOR VALUES FROM ('2024-1-1') TO ('2024-7-1');
CREATE TABLE test_multi_partition_a_l2_2 PARTITION OF test_multi_partition_a_l1
    FOR VALUES FROM ('2024-7-1') TO ('2025-1-1');
CREATE TABLE test_multi_partition_b_l2_1 PARTITION OF test_multi_partition_b_l1
    FOR VALUES FROM ('2025-1-1') TO ('2025-7-1');
CREATE TABLE test_multi_partition_b_l2_2 PARTITION OF test_multi_partition_b_l1
    FOR VALUES FROM ('2025-7-1') TO ('2026-1-1');

INSERT INTO test_multi_partition (sale_id, sale_date, amount)
SELECT (random() * 100)::int, '2024-01-1'::date + i, (random() * 1000)::numeric(15,2)
FROM generate_series(1, 730) i;

-- 同步所有层级分区
SELECT rds_duckdb.create_duckdb_tables('{
    test_multi_partition,
    test_multi_partition_a_l1, test_multi_partition_b_l1,
    test_multi_partition_a_l2_1, test_multi_partition_a_l2_2,
    test_multi_partition_b_l2_1, test_multi_partition_b_l2_2
}');
说明

若叶子分区未同步,查询根分区时可能因部分表缺失而触发 fallback。

分区表的 DDL 变更(如 ATTACH/DETACH PARTITION)同样受 enable_ddl_replication 控制,失败行为由 ddl_replication_fail_action 决定。

4.3 自动创建 DuckDB 表

说明

仅20260330 及以上版本支持。

除手动调用 create_duckdb_table() 外,rds_duckdb 支持自动创建。开启后,当在 PostgreSQL 中执行 CREATE TABLE 且满足同步条件时,系统会自动创建对应的 DuckDB 表并启动增量同步。

-- 开启自动创建(USERSET 级别,可会话级控制)
SET rds_duckdb.auto_create_duckdb_table = on;

-- 创建 PG 表,DuckDB 表会自动创建
CREATE TABLE auto_tbl(id int primary key, val text);
INSERT INTO auto_tbl VALUES (1, 'hello');

-- 直接查询 DuckDB 数据
/*+ set(rds_duckdb.execution on) */ SELECT * FROM auto_tbl;

预期结果(同步正常时):

  sync_table     | sync_status_description | sync_error_description
-----------------+-------------------------+------------------------
 public.auto_tbl | data syncing            | no errors

行为说明:

  • 仅对普通表生效(当前版本暂不考虑分区表的自动创建)。

  • 要求表具备主键或 REPLICA IDENTITY,否则无法进入 data syncing 状态。

  • 如果当前数据库尚未创建过任何 DuckDB 表,则不会触发自动创建。

4.4 自主 Fallback 策略

当 SQL 不满足 DuckDB 执行条件时,系统根据 rds_duckdb.enable_fallback 决定行为:

  • on(默认):自动回退到 PostgreSQL 执行,可配合 enable_log_warning 查看回退原因。

  • off:直接报错,强制暴露问题。

此外,支持超延迟回退(增量同步延迟)。参数 rds_duckdb.wait_sync_timeout 控制查询对增量同步位点的等待超时(单位:毫秒):

取值

含义

-1(默认)

不检查同步位点,直接执行。

0

直接比较 LSN,不等待。

> 0

最多等待指定毫秒,若 DuckDB 同步位点仍未追上当前事务的提交位点,则触发回退或报错。

触发场景:写入频繁、同步延迟较大时,查询若要求强一致性,可能因等待超时而回退。

日志示例enable_log_warning = on):

WARNING:  Fallback postgres due to waiting for incremental synchronization timeout

如果 enable_fallback = off,则报错:

ERROR:  RDS DuckDB: canceling statement due to waiting for incremental synchronization timeout

验证延迟:

-- 查看同步延迟
SELECT slot_name, pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn) AS lag_bytes
FROM pg_replication_slots
WHERE slot_name LIKE 'rds_duckdb_slot%';

4.5 执行成本阈值(plan_cost_threshold)

rds_duckdb.plan_cost_threshold 用于控制只有估算成本足够高的查询才转发到 DuckDB 执行,避免简单查询因 DuckDB 转发和启动开销而反而变慢。

参数

默认值

说明

rds_duckdb.plan_cost_threshold

0

成本阈值,单位与 PostgreSQL EXPLAIN 中的 cost 一致。0 表示不判断成本,所有符合条件的 SELECT 都尝试走 DuckDB。

典型使用场景:

  • 线上业务中既有复杂分析型 SQL(JOIN、聚合、大量扫描),也有简单的点查或小范围扫描。后者在 PostgreSQL 中执行反而更快,因为 DuckDB 的转发和连接初始化存在一定固定开销。

  • 设置一个合理的阈值(例如 100010000),可以让低成本的简单查询继续在 PostgreSQL 中执行,仅将高成本的大查询下推至 DuckDB 加速。

配置示例:

-- 设置成本阈值为 5000,仅当 PG 计划成本超过 5000 时才走 DuckDB
SET rds_duckdb.plan_cost_threshold = 5000;

-- 示例 1:简单点查,PG 计划成本低,保留在 PG 执行
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM my_table WHERE id = 1;

-- 示例 2:复杂聚合查询,PG 计划成本高,转发到 DuckDB
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT count(*), avg(amount) FROM my_table GROUP BY region;
说明

该参数仅影响成本判断阶段,不影响 fallback 机制。即使查询被转发到 DuckDB,若 DuckDB 执行器内部报错,仍会通过 fallback 回退到 PG。

阈值设置过高可能导致本可以加速的中等成本查询也留在 PG 执行;设置过低则无法过滤掉简单查询。建议根据实际业务负载逐步调整。

常见问题

为什么查询没有走 DuckDB?

通过参数 rds_duckdb.enable_fallback 可定位查询未走 DuckDB 的具体原因。

排查步骤:

-- 步骤 1:关闭 fallback,强制暴露真实原因
SET rds_duckdb.enable_fallback = off;

-- 步骤 2:执行目标 SQL
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM my_table;

可能遇到的报错及含义:

报错信息

含义

"my_table" is not a duckdb table or not in syncing status, and rds_duckdb.enable_fallback is set to off.

该表没有对应的 DuckDB 列存表,或不在 syncing 状态。

RDS DuckDB: canceling statement due to not in syncing status.

query_syncing_table = on 时,某张表尚未完成同步。

RDS DuckDB: canceling statement due to waiting for incremental synchronization timeout

同步延迟超过 wait_sync_timeout

Modification operations on DuckDB tables are currently not supported, fallback to PG.

尝试对 DuckDB 表执行 INSERT/UPDATE/DELETE。

常见 fallback 场景汇总:

场景

说明

表不是 DuckDB 表

未调用 create_duckdb_table()

表未在 syncing 状态

初始同步未完成、DDL 冲突、或没有主键。

增量同步延迟超时

rds_duckdb.wait_sync_timeout 设置下,等待同步超时。

DuckDB 不支持的语法

部分 SQL 特性 DuckDB 不支持,自动回退。

包含非 DuckDB 表

JOIN 查询中部分表未创建 DuckDB 副本。

可以通过视图 rds_duckdb.duckdb_sync_stat 查询每个 DuckDB 表的同步状态(需要通过高权限用户执行)。例如:

SELECT sync_table,
       sync_status_description,
       sync_error_description
FROM rds_duckdb.duckdb_sync_stat;

 sync_table        | sync_status_description | sync_error_description
-------------------+-------------------------+------------------------------------------
 test_schema.test1 | not syncing             | no primary key or replica identity index

如果期望查询到未增量同步表的数据,可以通过设置参数 rds_duckdb.query_syncing_table = off 完成。

相关链接