Todos os produtos
Search
Central de documentação

ApsaraDB RDS:Use the pg_hint_plan extension to customize query plans

Última atualização: Jun 26, 2026

A extensão pg_hint_plan permite substituir o planejador baseado em custo do PostgreSQL por hints incorporados em comentários SQL, como /*+ SeqScan(orders) */. Utilize-a quando o planejador selecionar um plano de consulta subotimizado impossível de corrigir apenas com atualizações de estatísticas ou alterações de índices.

Pré-requisitos

Antes de começar, verifique se você possui:

  • Uma instância RDS PostgreSQL 10 ou superior

  • Uma conta privilegiada na instância. Para criar uma, consulte Criar uma conta

Importante

Para o RDS PostgreSQL 17, a versão secundária do mecanismo deve ser 20241030 ou posterior. Caso não consiga criar a extensão, atualize a versão secundária do mecanismo primeiro.

Como funciona

O PostgreSQL utiliza um otimizador baseado em custo que estima o custo de cada plano de consulta possível e seleciona aquele com o menor valor. Como o otimizador trabalha com base em estatísticas, e não no seu conhecimento sobre os dados, ele pode ignorar padrões inerentes aos dados e escolher um plano subotimizado.

O pg_hint_plan lê hints especiais de comentários SQL e os transmite ao planejador antes da otimização. Isso permite especificar o método de varredura, o método de junção, a ordem de junção e outros comportamentos do planejador para uma consulta específica, sem modificar os dados ou as estatísticas.

Instale a extensão

Instalação pelo console

  1. Acesse a lista de instâncias RDS, selecione uma região e clique em ID da instância.

  2. No painel de navegação à esquerda, clique em Plug-ins.

  3. Na página Extension Management, clique em aba Uninstalled Extensions, pesquise por pg_hint_plan e clique em Install na coluna Actions.

    image

  4. Na caixa de diálogo, selecione o banco de dados de destino e uma conta privilegiada, depois clique em OK.

A instalação da extensão é concluída quando o status da instância muda de Maintaining Instance para Running.

Instalação via SQL

  1. Defina os parâmetros da instância para adicionar pg_hint_plan ao Running Value de shared_preload_libraries. Por exemplo:

    'pg_stat_statements,auto_explain,pg_hint_plan'
  2. Com uma conta privilegiada, conecte-se ao banco de dados onde deseja instalar a extensão e execute:

    CREATE EXTENSION pg_hint_plan;

Atualize ou desinstale a extensão

Na página Extension Management, clique em aba Installed Extensions:

  • Para atualizar: clique em Upgrade na coluna Actions. Se o botão Upgrade não aparecer, a extensão já está na versão mais recente.

  • Para desinstalar: clique em Uninstall na coluna Actions.

Para desinstalar via SQL:

DROP EXTENSION pg_hint_plan;

Escrever hints em comentários

Insira os hints em um comentário de bloco que começa com /*+ e termina com */, imediatamente antes da instrução SQL. Cada hint consiste em um nome e seus parâmetros entre parênteses, separados por espaços.

Exemplo

/*+
    HashJoin(a b)
    SeqScan(a)
  */
EXPLAIN SELECT *
   FROM test_table02 b
   JOIN test_table01 a ON b.bid = a.bid
  ORDER BY a.aid;

Saída:

QUERY PLAN
---------------------------------------------------------------------------------------
 Sort  (cost=31465.84..31715.84 rows=100000 width=197)
   Sort Key: a.aid
   ->  Hash Join  (cost=1.02..4016.02 rows=100000 width=197)
         Hash Cond: (a.bid = b.bid)
         ->  Seq Scan on test_table01 a  (cost=0.00..2640.00 rows=100000 width=97)
         ->  Hash  (cost=1.01..1.01 rows=1 width=100)
               ->  Seq Scan on test_table02 b  (cost=0.00..1.01 rows=1 width=100)
(7 rows)

Usar aliases de tabela nos hints

Se uma consulta utilizar um alias de tabela, o hint deve referenciar o alias, e não o nome original da tabela. O uso do nome original faz com que o sistema ignore o hint silenciosamente.

Hint com alias (efetivo):

Exemplo

/*+ IndexScan(t) */
EXPLAIN (COSTS OFF)
SELECT *
FROM tbl t
WHERE a = 1;
QUERY PLAN
-------------------------------------
 Index Scan using tbl_a_idx on tbl t
   Index Cond: (a = 1)

Hint sem alias (ignorado):

/*+ IndexScan(tbl) */
EXPLAIN (COSTS OFF)
SELECT *
FROM tbl t
WHERE a = 1;
QUERY PLAN
-------------------
 Seq Scan on tbl t
   Filter: (a = 1)

Usar a tabela de hints para SQL não editável

Quando não for possível modificar diretamente a instrução SQL, armazene os hints na tabela hint_plan.hints. Os hints nesta tabela têm precedência sobre os hints em comentários inline.

Nota

Por padrão, o usuário que cria a extensão pg_hint_plan possui permissões na tabela hint_plan.hints.

A tabela possui as seguintes colunas:

Coluna

Descrição

id

Identificador único da linha, gerado automaticamente.

norm_query_string

Padrão correspondente à instrução SQL alvo. Substitua todas as constantes por ?. Os espaços são significativos.

application_name

Nome da aplicação para escopo do hint. Deixe em branco para aplicar a todas as aplicações.

hints

Conteúdo do hint, sem as marcas de comentário /*+ */ ao redor.

Ative a tabela de hints

SET pg_hint_plan.enable_hint_table = on;

Gerencie hints na tabela

Inserir um hint:

INSERT INTO hint_plan.hints (norm_query_string, application_name, hints)
VALUES (
    'EXPLAIN (COSTS false) SELECT * FROM t1 WHERE t1.id = ?;',
    '',
    'SeqScan(t1)'
);

Atualize um hint:

UPDATE hint_plan.hints
SET hints = 'IndexScan(t1)'
WHERE id = 1;

Exclua um hint:

DELETE FROM hint_plan.hints
WHERE id = 1;

Tipos de hints

O pg_hint_plan suporta seis categorias de hints.

Hints de método de varredura

Forçam ou proíbem um método específico de varredura em uma tabela. Se a tabela possuir um alias na consulta, utilize-o no hint.

Válido em: tabelas comuns, tabelas herdadas, tabelas unlogged, tabelas temporárias, tabelas de sistema.

Não válido em: tabelas externas, funções de tabela, expressões de valor constante, expressões universais, views, subconsultas.

Exemplo — forçar uma varredura sequencial em t1 e uma varredura de índice em t2:

Exemplo

/*+
    SeqScan(t1)
    IndexScan(t2 t2_pkey)
 */
SELECT * FROM table1 t1 JOIN table2 t2 ON (t1.key = t2.key);

Hints de método de junção

Forçam ou proíbem um método específico de junção entre tabelas.

Válido em: tabelas comuns, tabelas herdadas, tabelas unlogged, tabelas temporárias, tabelas externas, tabelas de sistema, funções de tabela, expressões de valor constante, expressões universais.

Não válido em: views, subconsultas.

Hints de ordem de junção

Controlam a ordem em que as tabelas são unidas. Duas formas estão disponíveis:

  • Especificar apenas a ordem de junção (direção escolhida pelo planejador):

    /*+ Leading(t1 t2 t3) */
    SELECT * FROM table1 t1
        JOIN table2 t2 ON (t1.key = t2.key)
        JOIN table3 t3 ON (t2.key = t3.key);
  • Especificar a ordem e a direção da junção em cada nível:

    /*+ Leading((t1 t2) t3) */
    SELECT * FROM table1 t1
        JOIN table2 t2 ON (t1.key = t2.key)
        JOIN table3 t3 ON (t2.key = t3.key);

Exemplo

Hints de correção de número de linhas

Corrigem estimativas de contagem de linhas incorretas feitas pelo otimizador. Quatro métodos de correção estão disponíveis:

Exemplo

/*+ Rows(a b #10) */ SELECT ...;   -- Set the row count to 10
/*+ Rows(a b +10) */ SELECT ...;   -- Add 10 to the row count
/*+ Rows(a b -10) */ SELECT ...;   -- Subtract 10 from the row count
/*+ Rows(a b *10) */ SELECT ...;   -- Multiply the row count by 10

Hints de execução paralela

Definem o número de workers paralelos para uma tabela. Configure a contagem de workers como 0 para desativar a execução paralela.

O terceiro parâmetro controla quais configurações são alteradas:

  • soft (padrão): altera apenas max_parallel_workers_per_gather; o planejador controla as demais configurações.

  • hard: altera todas as configurações relacionadas do planejador.

Válido em: tabelas comuns, tabelas herdadas, tabelas unlogged, tabelas de sistema. Tabelas internas de uma view podem ser referenciadas pelo nome real ou alias.

Não válido em: tabelas externas, cláusulas de valor constante, expressões universais, views, subconsultas.

Exemplo — executar uma consulta de junção com 3 workers em c1 e 5 workers em c2:

Exemplo

EXPLAIN /*+ Parallel(c1 3 hard) Parallel(c2 5 hard) */
       SELECT c2.a FROM c1 JOIN c2 ON (c1.a = c2.a);
QUERY PLAN
-------------------------------------------------------------------------------
 Hash Join  (cost=2.86..11406.38 rows=101 width=4)
   Hash Cond: (c1.a = c2.a)
   ->  Gather  (cost=0.00..7652.13 rows=1000101 width=4)
         Workers Planned: 3
         ->  Parallel Seq Scan on c1  (cost=0.00..7652.13 rows=322613 width=4)
   ->  Hash  (cost=1.59..1.59 rows=101 width=4)
         ->  Gather  (cost=0.00..1.59 rows=101 width=4)
               Workers Planned: 5
               ->  Parallel Seq Scan on c2  (cost=0.00..1.59 rows=59 width=4)

Exemplo — agregação com 5 workers:

EXPLAIN /*+ Parallel(tl 5 hard) */ SELECT sum(a) FROM tl;
QUERY PLAN
-----------------------------------------------------------------------------------
 Finalize Aggregate  (cost=693.02..693.03 rows=1 width=8)
   ->  Gather  (cost=693.00..693.01 rows=5 width=8)
         Workers Planned: 5
         ->  Partial Aggregate  (cost=693.00..693.01 rows=1 width=8)
               ->  Parallel Seq Scan on tl  (cost=0.00..643.00 rows=20000 width=4)

Hints de parâmetros GUC

Alteram temporariamente o valor de um parâmetro GUC durante o planejamento da consulta. Se o mesmo parâmetro GUC for definido mais de uma vez, o último valor prevalecerá.

Exemplo

/*+ Set(random_page_cost 2.0) */
SELECT * FROM table1 t1 WHERE key = 'value';

Formatos de hints suportados

Categoria Formato Descrição
Métodos de varredura SeqScan(table) Força uma varredura sequencial.
TidScan(table) Força uma varredura TID (identificador de tupla).
IndexScan(table [index...]) Força uma varredura de índice. Opcionalmente, especifique o índice.
IndexOnlyScan(table [index...]) Força uma varredura somente de índice. Opcionalmente, especifique o índice.
BitmapScan(table [index...]) Força uma varredura de bitmap.
NoSeqScan(table) Proíbe uma varredura sequencial.
NoTidScan(table) Proíbe uma varredura TID.
NoIndexScan(table) Proíbe uma varredura de índice.
NoIndexOnlyScan(table) Proíbe uma varredura somente de índice. Apenas tabelas são varridas.
NoBitmapScan(table) Proíbe uma varredura de bitmap.
Métodos de junção NestLoop(table table [table...]) Força uma junção nested loop.
HashJoin(table table [table...]) Força uma junção hash.
MergeJoin(table table [table...]) Força uma junção merge.
NoNestLoop(table table [table...]) Proíbe uma junção nested loop.
NoHashJoin(table table [table...]) Proíbe uma junção hash.
NoMergeJoin(table table [table...]) Proíbe uma junção merge.
Ordem de junção Leading(table table [table...]) Especifica a ordem de junção.
Leading(<join pair>) Especifica a ordem e a direção da junção em cada nível.
Correção de número de linhas Rows(table table [table...] correction) Corrige a contagem estimada de linhas para uma junção. Métodos de correção: #<n> (definir como n), +<n> (adicionar n), -<n> (subtrair n), *<n> (multiplicar por n). <n> deve ser legível pela função strtod.
Execução paralela Parallel(table <workers> [soft|hard]) Define ou proíbe a execução paralela. Defina <workers> como 0 para desativar. Padrão: soft.
Parâmetros GUC Set(GUC-param value) Define o valor de um parâmetro GUC durante o planejamento da consulta.

Para mais informações, consulte pg_hint_plan.