Não, o PostgreSQL não aceita hints e nunca aceitará. É um erro achar
    que hints são uma solução para esse tipo de problemas, normalmente
    eles causam mais problemas do que resolvem. Nem sempre usar um
    índice é o melhor caminho para uma consulta e isso varia com o
    volume das tabelas envolvidas.


Flavio,
Discordo sobre Hints, pois imagine a situação abaixo:
//

torce_para        count(*)
--------------  ----------
São Paulo        4.000.000

Corinthians      8.000.000
Palmeiras        6.000.000
Santos           2.000.000
VOCEM de Assis           8

Se existe um índice em torce_para e uma query pedir todos os torcedores
do VOCEM de Assis, é muito provável que o PostgreSQL fará "Sequencial
Scan" (full table scan - Oracle).  É muito mais barato para o Otimizador
fazer um Sequencial Scan que um acesso a milhões de linhas do índice.

Ou o planejador do Oracle é uma bosta (e por isso precisa de hint mesmo pra funcionar) ou você se enganou, colega. Eu espero que você tenha realmente se enganado.

Veja meu exemplo, fiz agora aqui em cinco minutinhos e reproduzi seu cenário:

psql (9.3.4)
Digite "help" para ajuda.

flavio=# create table torcedores (torce_para text);
CREATE TABLE
flavio=# insert into torcedores (torce_para) select 'São Paulo' from (select generate_series (1, 4000000)) a;
INSERT 0 4000000
flavio=# insert into torcedores (torce_para) select 'Corinthians' from (select generate_series (1, 8000000)) a;
INSERT 0 8000000
flavio=# insert into torcedores (torce_para) select 'Palmeiras' from (select generate_series (1, 6000000)) a;
INSERT 0 6000000
flavio=# insert into torcedores (torce_para) select 'Santos' from (select generate_series (1, 2000000)) a;
INSERT 0 2000000
flavio=# insert into torcedores (torce_para) select 'VOCEM de Assis' from (select generate_series (1, 8)) a;
INSERT 0 8
flavio=# create index torce_para_idx on torcedores (torce_para);
CREATE INDEX

Agora o que interessa:

flavio=# SELECT torce_para, count(torce_para) FROM torcedores GROUP BY torce_para;
   torce_para   |  count
----------------+---------
 Corinthians    | 8000000
 Palmeiras      | 6000000
 Santos         | 2000000
 São Paulo      | 4000000
 VOCEM de Assis |       8
(5 registros)

flavio=# EXPLAIN ANALYZE SELECT * FROM torcedores WHERE torce_para = 'VOCEM de Assis'; QUERY PLAN


---------------------------------------------------------------------------------------------------------------------------------

Index Only Scan using torce_para_idx on torcedores (cost=0.56..8.58 rows=1 width=10) (actual time=0.341..0.343 rows=8 loops=1)

Index Cond: (torce_para = 'VOCEM de Assis'::text)


Heap Fetches: 8


Total runtime: 0.361 ms


(4 registros)

Logo, sua afirmativa é *errada* e o planejador do PostgreSQL entendeu direitinho que o índice é bastante útil ali. Vamos tentar para um dos outros times:

flavio=# EXPLAIN ANALYZE SELECT * FROM torcedores WHERE torce_para = 'Corinthians';

QUERY PLAN


---------------------------------------------------------------------------------------------------------------------------

Seq Scan on torcedores (cost=0.00..356142.50 rows=8000522 width=10) (actual time=336.863..2077.353 rows=8000000 loops=1)

Filter: (torce_para = 'Corinthians'::text)


Rows Removed by Filter: 12000008


Total runtime: 2356.269 ms


(4 registros)

Uhm... faz sentido, afinal, é uma fatia grande da tabela.

Agora vamos tentar imitar a ridícula funcionalidade "hint" do Oracle usando algo mais moderno:

flavio=# set enable_seqscan = off;
SET


flavio=# EXPLAIN ANALYZE SELECT * FROM torcedores WHERE torce_para = 'Corinthians';

QUERY PLAN --------------------------------------------------------------------------------------------------------------------------------------------

Bitmap Heap Scan on torcedores (cost=181688.61..387842.13 rows=8000522 width=10) (actual time=727.201..1726.837 rows=8000000 loops=1) Recheck Cond: (torce_para = 'Corinthians'::text)


Rows Removed by Index Recheck: 115


-> Bitmap Index Scan on torce_para_idx (cost=0.00..179688.48 rows=8000522 width=0) (actual time=725.187..725.187 rows=8000000 loops=1) Index Cond: (torce_para = 'Corinthians'::text)


 Total runtime: 2003.549 ms
(6 registros)

Você vai me dizer que isso saiu mais rápido que a consulta anterior, mas com custo mais alto, note. Saiu mais rápido por causa dos dados em cache do exemplo anterior, infelizmente.

Vou reiniciar o PostgreSQL e a máquina pra limpar o cache e refazer:

flavio=# set enable_seqscan = off;
SET
flavio=# EXPLAIN ANALYZE SELECT * FROM torcedores WHERE torce_para = 'Corinthians'; QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
Bitmap Heap Scan on torcedores (cost=183446.83..391336.64 rows=8067905 width=10) (actual time=764.227..1757.159 rows=8000000 loops=1)
   Recheck Cond: (torce_para = 'Corinthians'::text)
   Rows Removed by Index Recheck: 115
-> Bitmap Index Scan on torce_para_idx (cost=0.00..181429.85 rows=8067905 width=0) (actual time=762.044..762.044 rows=8000000 loops=1)
         Index Cond: (torce_para = 'Corinthians'::text)
 Total runtime: 10036.530 ms
(6 registros)

Uhm... é, 10 segundos pra usar o índice, 2 segundos pro seqscan.

Ainda bem que não meti um *hint* ali né?

Se voce tiver a possibilidade de inserir um Hint poderia resolver a
query muito mais rápido, forçando o uso do indice, pois sao somente 8
registros. Outra opção seria criar um Histograma.

Como mostrei, o PostgreSQL executou a consulta exatamente sobre o índice.
Sobre histogramas, o sistema de estatísticas do PostgreSQL usa exatamente esta técnica para determinar os custos.

Outro motivo que se utiliza Hint é para configurar grau de paralelismo
em queries, mas no PostgreSQL até a versão 8 eu sei que não tem isso
implementado. Alguém sabe se o PostgreSQL atual trabalha com paralelismo?

Do jeito que você está chamando de paralelismo, não, isso não existe internamente ainda hoje no PostgreSQL, estudos sobre isso estão em andamento.

        mais restritivos através de alias de tabela +- como abaixo, assim na
        hora da junção teria menos dados para fazer os Hash Join ou
        Nested Loop:

        SELECT *
        FROM C1,
        ( SELECT * FROM C2 WHERE FILTRO = QUALQUER ) C2A
        WHERE
                ....


    Você olhou a consulta do colega antes de dizer isso?


Não, acabei nao observando o Link para a Query!

Sem ressentimentos, acontece.
Agradecemos por ter respondido corretamente, sem top post, desta vez. Acho que não deixamos passar nada.

[]s
Flavio Gurgel
_______________________________________________
pgbr-geral mailing list
[email protected]
https://listas.postgresql.org.br/cgi-bin/mailman/listinfo/pgbr-geral

Responder a