すべてのプロダクト
Search
ドキュメントセンター

ApsaraDB RDS:DuckDB によるクエリの高速化方法

最終更新日:Jun 13, 2026

ApsaraDB RDS for PostgreSQL 向けの rds_duckdb 拡張機能は、分析用の SELECT クエリを自動的に DuckDB のカラムストアエンジンにオフロードします。これにより、アプリケーションの SQL を変更することなく複雑なクエリを高速化できます。本トピックでは、クエリのオフロード方法、高度な機能の利用方法、および一般的な問題のトラブルシューティングについて説明します。拡張機能および必要な DuckDB テーブルはすでに作成済みであることを前提としています。

この拡張機能に関するお問い合わせ、ディスカッション、フィードバックについては、DingTalk の ApsaraDB RDS for PostgreSQL 拡張機能コミュニティ (ID: 103525002795) にご参加ください。

前提条件

この機能を使用する前に、ご利用のインスタンスが以下の要件を満たしていることを確認してください。

  • プライマリインスタンスは、ApsaraDB RDS for PostgreSQL 13~18 で、マイナーエンジンバージョンが 20260130 以降である必要があります。読み取り専用インスタンスでクエリを高速化する場合は、バージョン 16~18 かつマイナーエンジンバージョンが 20260130 以降である必要があります。

  • パーティションテーブルの同期 または DuckDB テーブルの自動作成 機能を使用するには、マイナーエンジンバージョンが 20260330 以降である必要があります。

  • rds_duckdb 拡張が作成されました。

注意事項

  • rds_duckdb 拡張機能は現在、読み取り専用の SELECT クエリのみを高速化します。INSERT、UPDATE、DELETE などのデータ操作言語 (DML) 操作、データ定義言語 (DDL) 操作、および対応する DuckDB テーブルを持たないテーブルを含むクエリは、自動的に PostgreSQL にフォールバックされます。

  • ヒントワードは rds_duckdb.execution の設定にのみ対応しており、他のパラメーターには適用されません。

  • DMS は SQL ステートメントを再書き込みする可能性があるため、ヒントワードを使用して高速化を有効にしてください。

  • ポイントクエリや小規模範囲スキャンなどの単純なクエリは、転送および起動時のオーバーヘッドにより DuckDB 上で遅くなる場合があります。rds_duckdb.plan_cost_threshold パラメーターを使用して、低コストのクエリをフィルターで除外してください。詳細については、「4.5 実行コストのしきい値」をご参照ください。

操作手順

クエリ高速化プロセスは、高速化の有効化、クエリがオフロードされたことの検証、実行ログの確認という 3 つのステップで構成されます。

ステップ 1:DuckDB 高速化の有効化

SELECT クエリを DuckDB にオフロードするには、以下のいずれかの方法を使用します。

  1. 方法 1:ヒントワードの使用(文レベル)

    SELECT 文にヒントワードを追加して、そのクエリのみを高速化します。この方法は、一時的な検証や特定のスロークエリの高速化に最適です。

    /*+ set(rds_duckdb.execution on) */ SELECT * FROM my_table WHERE id = 1;
  2. 方法 2:セッションレベルパラメーターの設定

    現在のセッションで以下のコマンドを実行します。これにより、このセッション内で該当するすべてのクエリが DuckDB にオフロードされます。

    SET rds_duckdb.execution = on;

ステップ 2:オフロードの検証

実行計画を使用して、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)

ステップ 3:DuckDB ログの確認(任意)

rds_duckdb.enable_log_warning パラメーターは、WARNING レベルのメッセージをクライアントに送信するかどうかを制御します。これにより、クエリが DuckDB にオフロードされなかった理由を特定できます。

  1. WARNING 出力を有効にします。この変更はセッションレベルで即座に有効になります。

    SET rds_duckdb.enable_log_warning = on;
  2. クライアント出力を確認します。enable_log_warning = on の場合、以下のシナリオで WARNING が出力されます。

    • クエリが PostgreSQL にフォールバックされた場合: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_duckdb 拡張機能は、ApsaraDB RDS for PostgreSQL から DuckDB へのテーブル構造変更(DDL)の自動同期をサポートします。

パラメーター

説明

デフォルト

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;
-- セーブポイントによる DDL のロールバック
BEGIN;
SAVEPOINT s1;
ALTER TABLE tbl DROP COLUMN extra_1;
ROLLBACK TO SAVEPOINT s1;
COMMIT;

フォールバックをトリガーするサポートされていない DDL 操作の例:

-- テーブルスキーマの変更(fail_action 設定に応じて自動完全更新または競合が発生)
ALTER TABLE tbl SET SCHEMA nsp1;

-- プライマリキーの削除(同期が停止し、クエリが PostgreSQL にフォールバック)
ALTER TABLE tbl DROP CONSTRAINT tbl_pkey;

プライマリキーを削除すると、duckdb_sync_stat 内のテーブルのステータスが not syncing に変化し、クエリはもはや DuckDB 経由でルーティングされなくなります。この状態は、プライマリキーまたは REPLICA IDENTITY を復元し、テーブルを手動で更新するまで継続します。

4.2 パーティションテーブルの同期

説明

この機能は、マイナーエンジンバージョン 20260330 以降でのみサポートされます。

rds_duckdb 拡張機能は、単一レベルおよびマルチレベルの PostgreSQL パーティションテーブル を DuckDB に同期できます。

PostgreSQL パーティションテーブルの同期: パーティションテーブルを同期するには、ルートパーティションおよびすべてのリーフパーティション に対して DuckDB テーブルを作成する必要があります。以下の例は単一レベルのパーティションテーブルを使用しています。

-- PostgreSQL パーティションテーブルの作成
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
}');
説明

リーフパーティションが同期されていない場合、ルートパーティションに対するクエリはテーブルが不足しているためフォールバックをトリガーする可能性があります。

ATTACH/DETACH PARTITION などのパーティションテーブルに対する DDL 変更も、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;

-- PostgreSQL テーブルを作成(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 自律的フォールバック

rds_duckdb.enable_fallback パラメーターは、SQL ステートメントを DuckDB で実行できない場合のシステムの動作を制御します。

  • 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 に転送して実行することで、転送および起動時のオーバーヘッドにより単純なクエリが遅くなるのを防ぎます。

パラメーター

デフォルト

説明

rds_duckdb.plan_cost_threshold

0

コストのしきい値。単位は PostgreSQL の EXPLAIN に表示される cost と同じです。0 はコストを評価せず、該当するすべての SELECT 文が DuckDB の使用を試みることを意味します。

典型的なユースケース:

  • ワークロードに、結合、集約、大規模スキャンを含む複雑な分析 SQL クエリと、ポイントクエリや小規模範囲スキャンなどの単純なクエリの両方が含まれている場合。単純なクエリは、DuckDB でのオフロードおよび接続初期化の固定オーバーヘッドにより、PostgreSQL 上で実行した方が速くなることが多いです。

  • 100010000 などの適切なしきい値を設定することで、低コストの単純なクエリは引き続き PostgreSQL で実行され、高コストの大規模クエリのみが DuckDB にプッシュダウンされて高速化されます。

設定例:

-- コストのしきい値を 5000 に設定。PostgreSQL 実行計画のコストが 5000 を超えるクエリのみを DuckDB にオフロード
SET rds_duckdb.plan_cost_threshold = 5000;

-- 例 1:コストが低い PostgreSQL 実行計画を持つ単純なポイントクエリは PostgreSQL 上で実行されるまま
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM my_table WHERE id = 1;

-- 例 2:コストが高い PostgreSQL 実行計画を持つ複雑な集計クエリは DuckDB にオフロードされる
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT count(*), avg(amount) FROM my_table GROUP BY region;
説明

このパラメーターは コスト評価フェーズ のみに影響し、フォールバックメカニズムを変更しません。クエリが DuckDB にオフロードされたとしても、DuckDB エグゼキュータ内でエラーが発生した場合は依然として PostgreSQL にフォールバックされます。

しきい値を高すぎに設定すると、高速化の恩恵を受ける可能性のある中程度のコストのクエリがオフロードされなくなる可能性があります。逆に低すぎに設定すると、単純なクエリをフィルターで除外できなくなる可能性があります。実際のワークロードに基づいて、しきい値を徐々に調整してください。

よくある質問

クエリがオフロードされないのはなぜですか?

rds_duckdb.enable_fallback パラメーターを使用して、クエリが DuckDB にオフロードされなかった理由を特定します。

トラブルシューティング手順:

-- ステップ 1:根本原因を明らかにするためにフォールバックを無効化
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 カラムストアテーブルが存在しない、またはテーブルが同期中の状態にありません。

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.

INSERT、UPDATE、または DELETE 操作が試行されました。

一般的なフォールバックシナリオの概要:

シナリオ

説明

テーブルが DuckDB テーブルではない。

create_duckdb_table() が呼び出されていません。

テーブルが同期中の状態にない。

同期の初期化が未完了、DDL 競合が発生、またはテーブルにプライマリキーが存在しません。

増分同期がタイムアウトした。

同期の待機時間が rds_duckdb.wait_sync_timeout で指定された時間を超えました。

構文が DuckDB でサポートされていない。

DuckDB でサポートされていない一部の SQL 機能により、自動的にフォールバックがトリガーされます。

クエリに非 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 パラメーターを設定できます。

関連リンク