A extensão rds_duckdb para ApsaraDB RDS for PostgreSQL encaminha automaticamente consultas SELECT analíticas ao mecanismo orientado a colunas DuckDB. Esse recurso acelera significativamente consultas complexas sem exigir alterações nas instruções SQL. Este tópico descreve como encaminhar consultas ao DuckDB após criar a extensão e as tabelas correspondentes, além de abordar recursos avançados e métodos de solução de problemas.
Para dúvidas, discussões ou feedback sobre esta extensão, participe do grupo DingTalk ApsaraDB RDS for PostgreSQL Extensions (ID: 103525002795).
Pré-requisitos
Antes de usar este recurso, verifique se as seguintes condições foram atendidas:
A instância primária executa o ApsaraDB RDS for PostgreSQL 13 a 18 com versão secundária do mecanismo 20260130 ou posterior. Para acelerar consultas em instâncias somente leitura, essas instâncias devem executar o PostgreSQL 16 a 18 com versão secundária do mecanismo 20260130 ou posterior.
Para usar a sincronização de tabelas particionadas ou a criação automática de tabelas do DuckDB, a versão secundária do mecanismo deve ser 20260330 ou posterior.
A extensão rds_duckdb está criada.
Observações de uso
O rds_duckdb acelera apenas consultas SELECT de leitura. Instruções DML (INSERT, UPDATE e DELETE), instruções DDL e consultas que envolvem tabelas sem correspondentes no DuckDB retornam ao PostgreSQL por padrão.
Os hints suportam apenas o parâmetro
rds_duckdb.execution, sem suporte a outros parâmetros.Ao conectar-se à instância via DMS, use um hint para ativar a aceleração, pois o DMS reescreve as instruções SQL.
Consultas simples, como point queries e varreduras de pequeno intervalo, podem apresentar desempenho inferior no DuckDB devido à sobrecarga de encaminhamento e inicialização. Configure
rds_duckdb.plan_cost_thresholdpara filtrar consultas de baixo custo. Para mais informações, consulte Limiar de custo de execução (plan_cost_threshold).
Procedimento
A aceleração de consultas envolve três etapas: ativar a aceleração, verificar o encaminhamento da consulta e visualizar os logs de execução.
Etapa 1: Ativar a aceleração do DuckDB
Use um dos métodos abaixo para encaminhar consultas SELECT ao DuckDB:
-
Método 1: Usar um hint (nível de instrução)
Adicione um hint antes da instrução SELECT. O hint aplica-se exclusivamente a essa instrução, sendo ideal para verificações temporárias ou para acelerar uma única consulta lenta:
/*+ set(rds_duckdb.execution on) */ SELECT * FROM my_table WHERE id = 1; -
Método 2: Configurar um parâmetro no nível de sessão
Execute o comando a seguir na sessão atual. Todas as consultas elegíveis da sessão serão enviadas ao DuckDB:
SET rds_duckdb.execution = on;
Etapa 2: Verificar o encaminhamento da consulta (EXPLAIN / EXPLAIN ANALYZE)
Analise o plano de execução para confirmar se uma instrução SQL foi encaminhada ao DuckDB.
-
Exemplo 1: Consulta de tabela única encaminhada ao DuckDB
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM test_hint;O plano esperado contém
Custom Scan (DuckDBScan)eDuckDB 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 │ └───────────────────────────┘ -
Exemplo 2: Retorno ao plano nativo do PostgreSQL após desativar o encaminhamento
/*+ set(rds_duckdb.execution off) */ EXPLAIN SELECT * FROM test_hint;Plano esperado:
QUERY PLAN ----------------------- Seq Scan on test_hint (1 row)
Etapa 3: Visualizar logs do DuckDB (opcional)
O parâmetro rds_duckdb.enable_log_warning controla o retorno de mensagens WARNING ao cliente, facilitando a identificação do motivo pelo qual uma consulta não foi executada pelo DuckDB.
-
Ative a saída de WARNING (efeito imediato no nível de sessão):
SET rds_duckdb.enable_log_warning = on; -
Verifique a saída do cliente. Com
enable_log_warning = on, mensagens WARNING são retornadas nos seguintes cenários:Retorno da instrução SQL ao PostgreSQL:
Fallback postgres due to ...Operações de escrita não suportadas:
Modification operations on DuckDB tables are currently not supported, fallback to PG.Instrução que não requer execução pelo DuckDB:
Statements don't need to be handed over to DuckDB, fallback to PG.
Quando enable_log_warning = off (padrão), as mensagens acima são gravadas nos logs no nível DEBUG1 e não são retornadas ao cliente.
Recursos avançados
Os recursos a seguir ajudam a otimizar o desempenho da aceleração ou a ampliar o escopo de sincronização. Ative-os conforme as necessidades do seu negócio.
Sincronização automática de DDL
Alterações de esquema (DDL) no ApsaraDB RDS for PostgreSQL podem ser sincronizadas automaticamente com o DuckDB. Os parâmetros abaixo controlam essa sincronização:
|
Parâmetro |
Descrição |
Valor padrão |
|
|
Define se a sincronização de DDL deve ser ativada. |
|
|
|
Ação a ser tomada em caso de falha na sincronização: |
|
Operações DDL suportadas e verificadas:
-- Add a column
ALTER TABLE tbl ADD COLUMN extra_1 int;
-- Drop a column
ALTER TABLE tbl DROP COLUMN extra_1;
-- Add a column with a default value
ALTER TABLE tbl ADD COLUMN extra_1 int DEFAULT 0;
-- Drop the default value
ALTER TABLE tbl ALTER COLUMN extra_1 DROP DEFAULT;
-- Change the column type
ALTER TABLE tbl ALTER COLUMN extra_1 TYPE varchar;
-- Rename a column
ALTER TABLE tbl RENAME COLUMN extra_1 TO extra_2;
-- Rename a table
ALTER TABLE tbl RENAME TO tbl_new;
-- DDL within a transaction
BEGIN;
ALTER TABLE tbl ADD COLUMN extra_3 int;
INSERT INTO tbl VALUES (..., 1);
COMMIT;
-- Roll back DDL by using a savepoint
BEGIN;
SAVEPOINT s1;
ALTER TABLE tbl DROP COLUMN extra_1;
ROLLBACK TO SAVEPOINT s1;
COMMIT;
Exemplos de operações DDL não suportadas que acionam o fallback:
-- Change the schema of a table (triggers an automatic full refresh or a conflict based on the fail_action setting)
ALTER TABLE tbl SET SCHEMA nsp1;
-- Drop the primary key (interrupts synchronization, and queries fall back to PostgreSQL)
ALTER TABLE tbl DROP CONSTRAINT tbl_pkey;
Após a remoção da chave primária, a tabela entra no estado not syncing em duckdb_sync_stat. As consultas deixam de ser executadas pelo DuckDB até que a chave primária ou REPLICA IDENTITY seja restaurada e a tabela seja atualizada manualmente.
Sincronização de tabelas particionadas
Este recurso é suportado apenas em instâncias com versão secundária do mecanismo 20260330 ou posterior.
O rds_duckdb consegue sincronizar tabelas particionadas do PostgreSQL (de nível único e multinível) com o DuckDB.
Para sincronizar uma tabela particionada do PostgreSQL, crie tabelas do DuckDB para a partição raiz e todas as partições folha. O exemplo abaixo ilustra uma tabela particionada de nível único:
-- Create a partitioned table in 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;
-- Synchronize the root partition and all leaf partitions to DuckDB
SELECT rds_duckdb.create_duckdb_tables('{test_partition, test_partition_a, test_partition_b, test_partition_c}');
Exemplo de consulta na partição raiz:
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM test_partition WHERE age >= 10 AND age < 20;
Plano esperado (apenas as partições atingidas são varridas após o pruning):
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│
└───────────────────────────┘└───────────────────────────┘
Tabelas particionadas multinível também são suportadas. Exemplo:
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;
-- Synchronize the partitions at all levels
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
}');
Se as partições folha não forem sincronizadas, uma consulta na partição raiz poderá acionar o fallback devido à ausência de tabelas.
Alterações de DDL em tabelas particionadas, como ATTACH PARTITION e DETACH PARTITION, também são controladas por enable_ddl_replication. O comportamento em caso de falha é determinado por ddl_replication_fail_action.
Criação automática de tabelas do DuckDB
Este recurso é suportado apenas em instâncias com versão secundária do mecanismo 20260330 ou posterior.
Além de chamar manualmente create_duckdb_table(), o rds_duckdb permite criar automaticamente tabelas do DuckDB. Com a criação automática ativada, ao executar CREATE TABLE no PostgreSQL e atender às condições de sincronização, o sistema cria automaticamente a tabela correspondente no DuckDB e inicia a sincronização incremental.
-- Enable automatic creation (USERSET level; can be controlled at the session level)
SET rds_duckdb.auto_create_duckdb_table = on;
-- Create a table in PostgreSQL, and the DuckDB table is automatically created
CREATE TABLE auto_tbl(id int primary key, val text);
INSERT INTO auto_tbl VALUES (1, 'hello');
-- Query DuckDB data directly
/*+ set(rds_duckdb.execution on) */ SELECT * FROM auto_tbl;
Resultado esperado (quando a sincronização está normal):
sync_table | sync_status_description | sync_error_description
-----------------+-------------------------+------------------------
public.auto_tbl | data syncing | no errors
Observações sobre o comportamento:
Este recurso aplica-se exclusivamente a tabelas regulares. A criação automática para tabelas particionadas não é suportada na versão atual.
A tabela precisa ter uma chave primária ou REPLICA IDENTITY. Caso contrário, não entrará no estado
data syncing.A criação automática não é acionada se nenhuma tabela do DuckDB tiver sido criada no banco de dados atual.
Política de fallback
Quando uma instrução SQL não atende às condições para execução pelo DuckDB, o parâmetro rds_duckdb.enable_fallback define o comportamento:
on (padrão): A consulta retorna automaticamente ao PostgreSQL. Configure
enable_log_warningpara visualizar o motivo do fallback.off: Um erro é retornado diretamente para expor o problema.
Além disso, há suporte a fallback para atrasos excessivos na sincronização incremental. O parâmetro rds_duckdb.wait_sync_timeout especifica o tempo máximo que uma consulta aguarda pela posição de sincronização incremental. Unidade: milissegundos:
|
Valor |
Descrição |
|
|
A posição de sincronização não é verificada e a consulta é executada diretamente. |
|
|
O LSN é comparado diretamente, sem espera. |
|
|
A consulta aguarda até o número especificado de milissegundos. Se a posição de sincronização do DuckDB ainda estiver atrasada em relação à posição de commit da transação atual, o fallback é acionado ou um erro é retornado. |
Cenário de acionamento: Em casos de escritas frequentes e alto atraso de sincronização, consultas que exigem consistência forte podem sofrer fallback devido ao tempo limite de espera.
Exemplo de log (enable_log_warning = on):
WARNING: Fallback postgres due to waiting for incremental synchronization timeout
Se enable_fallback = off, um erro é retornado:
ERROR: RDS DuckDB: canceling statement due to waiting for incremental synchronization timeout
Verificar o atraso de sincronização:
-- View synchronization lag
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%';
Limiar de custo de execução (plan_cost_threshold)
O parâmetro rds_duckdb.plan_cost_threshold garante que apenas consultas com custos estimados suficientemente altos sejam encaminhadas ao DuckDB. Isso evita que consultas simples fiquem mais lentas devido à sobrecarga de encaminhamento e inicialização do DuckDB.
|
Parâmetro |
Valor padrão |
Descrição |
|
|
|
Limiar de custo, na mesma unidade do |
Cenários típicos:
Uma carga de trabalho online contém tanto instruções SQL analíticas complexas (JOINs, agregações e grandes varreduras) quanto point queries simples ou varreduras de pequeno intervalo. Estas últimas executam mais rápido no PostgreSQL, pois o DuckDB incorre em sobrecarga fixa para encaminhamento e inicialização de conexão.
Ao definir um limiar adequado, como
1000ou10000, consultas simples de baixo custo continuam a rodar no PostgreSQL, enquanto apenas consultas pesadas de alto custo são enviadas ao DuckDB para aceleração.
Exemplo de configuração:
-- Set the cost threshold to 5000. Only queries whose PostgreSQL plan costs exceed 5000 are forwarded to DuckDB
SET rds_duckdb.plan_cost_threshold = 5000;
-- Example 1: A simple point query whose PostgreSQL plan cost is low remains in PostgreSQL
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM my_table WHERE id = 1;
-- Example 2: A complex aggregation query whose PostgreSQL plan cost is high is forwarded to DuckDB
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT count(*), avg(amount) FROM my_table GROUP BY region;
Este parâmetro afeta apenas a fase de avaliação de custo e não interfere no mecanismo de fallback. Mesmo que uma consulta seja encaminhada ao DuckDB, ela ainda retornará ao PostgreSQL se ocorrer um erro dentro do executor do DuckDB.
Um limiar muito alto pode manter no PostgreSQL consultas de custo médio que poderiam ser aceleradas. Um limiar muito baixo impede a filtragem de consultas simples. Ajuste o valor gradualmente com base na sua carga de trabalho real.
Perguntas frequentes
Por que uma consulta não é executada pelo DuckDB?
O parâmetro rds_duckdb.enable_fallback ajuda a identificar o motivo específico pelo qual uma consulta não foi executada pelo DuckDB.
Etapas de solução de problemas:
-- Step 1: Disable fallback to expose the actual cause
SET rds_duckdb.enable_fallback = off;
-- Step 2: Run the target SQL statement
/*+ set(rds_duckdb.execution on) */ EXPLAIN SELECT * FROM my_table;
Possíveis erros e seus significados:
|
Erro |
Significado |
|
|
A tabela não possui uma tabela orientada a colunas correspondente no DuckDB ou não está no estado de sincronização. |
|
|
Quando |
|
|
O atraso de sincronização excede |
|
|
Foi tentada uma operação INSERT, UPDATE ou DELETE em uma tabela do DuckDB. |
Cenários comuns de fallback:
|
Cenário |
Descrição |
|
A tabela não é uma tabela do DuckDB |
|
|
A tabela não está no estado de sincronização |
A sincronização inicial está incompleta, ocorreu um conflito de DDL ou a tabela não tem chave primária. |
|
Tempo limite de sincronização incremental |
A espera pela sincronização expirou com base na configuração |
|
Sintaxe não suportada pelo DuckDB |
O DuckDB não suporta alguns recursos SQL e a consulta retorna automaticamente ao PostgreSQL. |
|
A consulta envolve tabelas fora do DuckDB |
Algumas tabelas em uma consulta JOIN não possuem correspondentes no DuckDB. |
Consulte o status de sincronização de cada tabela do DuckDB usando a view rds_duckdb.duckdb_sync_stat. É necessária uma conta privilegiada. Exemplo:
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
Para consultar dados de tabelas que não estão sincronizadas incrementalmente, defina o parâmetro rds_duckdb.query_syncing_table = off.