O pg_hint_plan permite incorporar dicas de plano de execução diretamente em comentários SQL, substituindo o otimizador baseado em custo do PolarDB consulta a consulta, sem afetar o restante da sessão.
/*+ SeqScan(a) HashJoin(a b) */
SELECT * FROM orders a JOIN customers b ON a.customer_id = b.id;
Como o pg_hint_plan funciona
O otimizador do PolarDB seleciona planos de execução com base em estatísticas de dados, e não em regras estáticas. Ele avalia todos os planos candidatos e escolhe aquele com o menor custo estimado. Embora essa abordagem funcione bem na maioria dos casos, o otimizador pode não identificar relações de dados menos óbvias e escolher um plano subotimizado.
Os parâmetros Grand Unified Scheme (GUC) permitem ajustar o otimizador, mas as alterações se aplicam a toda a sessão. Use o pg_hint_plan quando precisar ajustar uma única consulta sem gerar efeitos colaterais em nível de sessão.
Versões compatíveis
O pg_hint_plan está disponível nas seguintes versões:
PolarDB for PostgreSQL 16 (versão de revisão 2.0.16.9.6.0 ou posterior)
PolarDB for PostgreSQL 14 (sem exigência de versão de revisão)
PolarDB for PostgreSQL 11 (sem exigência de versão de revisão)
Para verificar a versão do seu cluster, execute SHOW polardb_version; no banco de dados ou visualize-a no console do PolarDB. Caso a versão de revisão não atenda ao requisito, atualize-a.
Pré-requisitos
Antes de começar, verifique se você tem:
Um cluster PolarDB for PostgreSQL executando uma versão compatível
Acesso ao banco de dados fora do Data Management (DMS) — o DMS não oferece suporte a dicas
Instalar e carregar o pg_hint_plan
Etapa 1: Criar a extensão
CREATE EXTENSION pg_hint_plan;
Etapa 2: Carregar a extensão
Escolha um dos métodos de carregamento abaixo conforme o escopo desejado:
Para um único usuário:
ALTER USER <username> SET session_preload_libraries = 'pg_hint_plan';
Para um único banco de dados:
ALTER DATABASE <database_name> SET session_preload_libraries = 'pg_hint_plan';
Se uma configuração incorreta impedir o login, conecte-se por meio de outra conta ou banco de dados e execute:
ALTER USER <username> RESET session_preload_libraries;
ALTER DATABASE <database_name> RESET session_preload_libraries;
Para um cluster de banco de dados:
Acesse o Quota Center, localize o item de cota chamado PolarDB PG pg_hint_plan use e clique em Apply na coluna Actions.
Etapa 3: Verificar se a extensão foi carregada
-
Ative a saída de depuração:
SET pg_hint_plan.debug_print TO on; SET pg_hint_plan.message_level TO notice; -
Execute uma consulta de teste com uma dica:
/*+Set(enable_seqscan 1)*/SELECT 1;Se a extensão estiver carregada, a seguinte saída será exibida:
NOTICE: pg_hint_plan: used hint: Set(enable_seqscan 1) -
Redefina as configurações de depuração:
RESET pg_hint_plan.debug_print; RESET pg_hint_plan.message_level;
Sintaxe das dicas
Um bloco de dicas começa com /*+ e termina com */. Cada dica consiste em um nome seguido de parênteses com os respectivos parâmetros, separados por espaços. Para melhorar a legibilidade, coloque múltiplas dicas em linhas separadas.
/*+
HashJoin(a b)
SeqScan(a)
*/
EXPLAIN SELECT *
FROM pgbench_branches b
JOIN pgbench_accounts a ON b.bid = a.bid
ORDER BY a.aid;
Resultado:
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 pgbench_accounts a (cost=0.00..2640.00 rows=100000 width=97)
-> Hash (cost=1.01..1.01 rows=1 width=100)
-> Seq Scan on pgbench_branches b (cost=0.00..1.01 rows=1 width=100)
(7 rows)
Regras de comportamento
O
pg_hint_planlê dicas apenas do primeiro bloco de comentários. Dicas em blocos subsequentes são ignoradas.Caracteres aceitos nas dicas: letras, dígitos, espaços e
_,,,(,). Qualquer outro caractere interrompe a análise imediatamente.A correspondência de nomes de objetos diferencia maiúsculas de minúsculas (case-sensitive), diferentemente do comportamento padrão do PostgreSQL.
Exemplo — distinção entre maiúsculas e minúsculas:
Se o seu banco de dados tiver uma tabela chamada tbl, a dica a seguir não fará correspondência com ela, pois TBL e tbl são tratados como nomes diferentes:
/*+ SeqScan(TBL) */
SELECT * FROM tbl;
Use o nome exato ou o alias conforme aparece na consulta:
/*+ SeqScan(tbl) */
SELECT * FROM tbl;
Limitações em stored procedures PL/pgSQL
Ao usar o pg_hint_plan dentro de stored procedures PL/pgSQL, as dicas têm efeito apenas nos seguintes tipos de instrução:
SELECT,INSERT,UPDATEeDELETERETURN QUERYEXECUTE QUERYOPENFOR
Posicione a dica imediatamente após a primeira palavra da instrução SQL. Se colocada antes da primeira palavra, ela não será reconhecida como parte da consulta.
Tipos de dicas
O pg_hint_plan oferece suporte a seis tipos de dicas.
Dicas para métodos de varredura
Especifique o método de varredura para uma tabela. Se a tabela possuir um alias, consulte-a pelo alias.
Aplica-se a: tabelas comuns, tabelas herdadas, tabelas unlogged, tabelas temporárias, tabelas de sistema
Não se aplica a: tabelas externas, funções de tabela, expressões de valor constante, expressões universais, views, subconsultas
/*+
SeqScan(t1)
IndexScan(t2 t2_pkey)
*/
SELECT * FROM table1 t1 JOIN table2 t2 ON (t1.key = t2.key);
Dicas para métodos de junção
Defina o método de junção para duas ou mais tabelas.
Aplica-se a: 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 se aplica a: views e subconsultas
Dicas para ordem de junção
Determine a ordem em que as tabelas são unidas. Duas abordagens estão disponíveis:
Especificar a ordem de junção sem restringir a direção em cada nível.
Especificar a ordem e a direção da junção em cada nível.
/*+
NestLoop(t1 t2)
MergeJoin(t1 t2 t3)
Leading(t1 t2 t3)
*/
SELECT * FROM table1 t1
JOIN table2 t2 ON (t1.key = t2.key)
JOIN table3 t3 ON (t2.key = t3.key);
Neste exemplo:
NestLoop(t1 t2)— une t1 e t2 usando nested loop joinMergeJoin(t1 t2 t3)— une t1, t2 e t3 usando merge joinLeading(t1 t2 t3)— define a ordem de junção como t1 → t2 → t3
Dicas para correção de número de linhas
Corrija estimativas de contagem de linhas calculadas incorretamente pelo otimizador. Quatro operadores têm suporte:
/*+ Rows(a b #10) */ SELECT ...; -- Set join result row count to 10
/*+ Rows(a b +10) */ SELECT ...; -- Increase row count by 10
/*+ Rows(a b -10) */ SELECT ...; -- Decrease row count by 10
/*+ Rows(a b *10) */ SELECT ...; -- Multiply row count by 10
Dicas para execução paralela
Especifique o plano de execução paralela para uma consulta.
Aplica-se a: tabelas comuns, tabelas herdadas, tabelas unlogged, tabelas de sistema
Não se aplica a: tabelas externas, cláusulas de valor constante, expressões universais, views, subconsultas
Use o nome real da tabela ou o alias para especificar tabelas internas dentro de uma view.
Exemplo 1: Defina o grau de paralelismo (DOP) como 3 para c1 e 5 para c2:
EXPLAIN /*+ Parallel(c1 3 hard) Parallel(c2 5 hard) */
SELECT c2.a FROM c1 JOIN c2 ON (c1.a = c2.a);
Resultado:
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 2: Defina o DOP para tl como 5:
EXPLAIN /*+ Parallel(tl 5 hard) */ SELECT sum(a) FROM tl;
Resultado:
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)
Dicas para definição de parâmetros GUC
Altere temporariamente o valor de um parâmetro GUC durante o planejamento da consulta. Ao contrário das alterações de GUC em nível de sessão, essas dicas afetam apenas a geração do plano de execução da consulta alvo. Se múltiplas dicas definirem o mesmo parâmetro GUC, a última terá efeito.
/*+ Set(random_page_cost 2.0) */
SELECT * FROM table1 t1 WHERE key = 'value';
Referência de sintaxe das dicas
Todas as dicas com suporte estão listadas abaixo. Parâmetros opcionais aparecem entre colchetes ([ ]).
| Tipo | Sintaxe | Descrição |
|---|---|---|
| Métodos de varredura | SeqScan(table) |
Força uma varredura sequencial |
TidScan(table) |
Força uma varredura TID | |
IndexScan(table [index...]) |
Força uma varredura de índice; opcionalmente especifique um índice | |
IndexOnlyScan(table [index...]) |
Força uma varredura apenas por índice; opcionalmente especifique um índice | |
BitmapScan(table [index...]) |
Força uma varredura de bitmap; opcionalmente especifique um índice | |
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 apenas por índice | |
NoBitmapScan(table) |
Proíbe uma varredura de bitmap | |
| Métodos de junção | NestLoop(table table [table...]) |
Força uma junção por nested loop |
HashJoin(table table [table...]) |
Força uma junção por hash | |
MergeJoin(table table [table...]) |
Força uma junção por merge | |
NoNestLoop(table table [table...]) |
Proíbe uma junção por nested loop | |
NoHashJoin(table table [table...]) |
Proíbe uma junção por hash | |
NoMergeJoin(table table [table...]) |
Proíbe uma junção por 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 de um resultado de junção; operadores: #<n>, +<n>, -<n>, *<n> |
| Execução paralela | Parallel(table <# of workers> [soft|hard]) |
Define ou proíbe execução paralela para a tabela especificada; 0 workers proíbe o paralelismo; soft (padrão) ajusta apenas max_parallel_workers_per_gather; hard ajusta todos os parâmetros relacionados |
PX(<# of workers>) |
Especifica execução paralela entre nós; <# of workers> define o DOP |
|
NoPX() |
Proíbe execução paralela entre nós | |
| Definição de parâmetro GUC | Set(GUC-param value) |
Define o valor de um parâmetro GUC durante o planejamento da consulta |
Durante a execução paralela entre nós, a dica Rows(...) não tem suporte. Dicas de método de junção podem ter como alvo apenas duas tabelas por vez, e dicas de ordem de junção devem especificar todas as tabelas envolvidas.