全部產品
Search
文件中心

ApsaraDB RDS:如何使用DuckDB加速查詢?

更新時間:Jun 12, 2026

RDS PostgreSQL 通過 rds_duckdb 外掛程式將分析型 SELECT 查詢自動轉寄至 DuckDB 列存引擎執行,顯著加快複雜查詢的響應速度,且無需修改業務 SQL。本文介紹在已完成外掛程式建立和 DuckDB 表建立的前提下,如何將查詢轉寄到 DuckDB 執行,以及相關進階功能與排查方法。

您可以加入RDS PostgreSQL外掛程式交流DingTalk群(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 完成。

相關連結