Para elaborar a resposta da @ alci:
O PostgreSQL não se importa em que ordem você escreve as coisas
O PostgreSQL não se importa com a ordem das entradas em uma WHERE
cláusula e escolhe índices e ordem de execução com base apenas na estimativa de custo e seletividade.
A ordem na qual as junções são gravadas também é ignorada até o configurado join_collapse_limit
; se houver mais junções do que isso, elas serão executadas na ordem em que foram gravadas.
As subconsultas podem ser executadas antes ou depois da consulta que as contém, dependendo do que for mais rápido, desde que a subconsulta seja executada antes da consulta externa realmente precisar das informações. Freqüentemente, na realidade, a subconsulta é executada meio que no meio ou intercalada com a consulta externa.
Não há garantia de que o PostgreSQL realmente execute partes da consulta. Eles podem ser completamente otimizados. Isso é importante se você chamar funções com efeitos colaterais.
O PostgreSQL transformará sua consulta
O PostgreSQL transformará fortemente as consultas, mantendo exatamente os mesmos efeitos, para fazê-las rodar mais rápido sem alterar os resultados.
Termos fora de uma subconsulta podem ser empurrados para baixo na subconsulta, para que sejam executados como parte da subconsulta, não onde você os escreveu na consulta externa
Os termos na subconsulta podem ser puxados para a consulta externa, para que sua execução seja feita como parte da consulta externa, não onde você os escreveu na subconsulta
A subconsulta pode, e geralmente é, achatada em uma junção na tabela externa. O mesmo vale para coisas como EXISTS
e NOT EXISTS
consultas.
As visualizações são achatadas na consulta que usa a visualização
As funções SQL geralmente são incorporadas à consulta de chamada
... e existem inúmeras outras transformações feitas em consultas, como pré-avaliação de expressão constante, desacorrelação de algumas subconsultas e todos os tipos de outros truques do planejador / otimizador.
Em geral, o PostgreSQL pode transformar e reescrever massivamente sua consulta, até o ponto em que cada uma dessas consultas:
select my_table.*
from my_table
left join other_table on (my_table.id = other_table.my_table_id)
where other_table.id is null;
select *
from my_table
where not exists (
select 1
from other_table
where other_table.my_table_id = my_table.id
);
select *
from my_table
where my_table.id not in (
select my_table_id
from other_table
where my_table_id is not null
);
geralmente todos produzem exatamente o mesmo plano de consulta. (Supondo que eu não tenha cometido nenhum erro estúpido acima).
Não é incomum tentar otimizar uma consulta apenas para descobrir que o planejador de consultas já descobriu os truques que você está tentando e os aplicou automaticamente, para que a versão otimizada à mão não seja melhor que a original.
Limitações
O planejador / otimizador está longe de ser insuficiente e é limitado pelo requisito de ter certeza absoluta de que não pode alterar os efeitos da consulta, os dados disponíveis para tomar decisões, as regras implementadas e o tempo da CPU pode gastar pensando nas otimizações. Por exemplo:
O planejador conta com as estatísticas mantidas por ANALYZE
(geralmente via autovacuum). Se estes estiverem desatualizados, a escolha do plano pode ser ruim.
As estatísticas são apenas uma amostra, portanto, podem ser enganosas devido aos efeitos de amostragem, especialmente se uma amostra muito pequena for coletada. Más escolhas de plano podem resultar.
As estatísticas não acompanham alguns tipos de dados sobre a tabela, como correlações entre colunas. Isso pode levar o planejador a tomar más decisões quando assume que as coisas são independentes quando não são.
O planejador se baseia em parâmetros de custo, como random_page_cost
a velocidade relativa de várias operações no sistema específico em que está instalado. Estes são apenas guias. Se estiverem muito errados, podem levar a más escolhas de plano.
Qualquer subconsulta com LIMIT
ou OFFSET
não pode ser achatada ou sujeita a pull / pushdown. Isso não significa que ele vai executar antes de todas as partes da consulta externa, embora, ou mesmo que ele vai executar em tudo .
Os termos CTE (as cláusulas de uma WITH
consulta) são sempre executados em sua totalidade, se são executados. Eles não podem ser achatados e os termos não podem ser empurrados para cima ou para baixo através da barreira de termos do CTE. Os termos CTE são sempre executados antes da consulta final. Esse é um comportamento não padrão do SQL , mas está documentado como o PostgreSQL faz as coisas.
O PostgreSQL possui uma capacidade limitada de otimizar consultas em tabelas, security_barrier
visualizações e outros tipos especiais de relação
O PostgreSQL não incorporará uma função escrita em nada, exceto SQL simples, nem fará pull / pushdown entre ela e a consulta externa.
O planejador / otimizador é realmente burro em selecionar índices de expressão e em diferenças triviais de tipo de dados entre índice e expressão.
Toneladas mais também.
Sua pergunta
No caso da sua consulta:
select 1
from workdays day
where day.date_day >= '2014-10-01'
and day.date_day <= '2015-09-30'
and day.offer_id in (
select offer.offer_day
from offer
inner join province on offer.id_province = province.id_province
inner join center cr on cr.id_cr = province.id_cr
where upper(offer.code_status) <> 'A'
and province.id_region in ('10' ,'15' ,'21' ,'26' ,'31' , ...,'557')
and province.id_cr in ('9' ,'14' ,'20' ,'25' ,'30' ,'35' ,'37')
)
nada impede que seja achatado em uma consulta mais simples com um conjunto extra de junções, e provavelmente será.
Provavelmente resultará em algo como (não testado, obviamente):
select 1
from workdays day
inner join offer on day.offer_id = offer.offer_day
inner join province on offer.id_province = province.id_province
inner join center cr on cr.id_cr = province.id_cr
where upper(offer.code_status) <> 'A'
and province.id_region in ('10' ,'15' ,'21' ,'26' ,'31' , ...,'557')
and province.id_cr in ('9' ,'14' ,'20' ,'25' ,'30' ,'35' ,'37')
and day.date_day >= '2014-10-01'
and day.date_day <= '2015-09-30';
O PostgreSQL otimizará a ordem de junção e os métodos de junção com base em suas estimativas de seletividade e contagem de linhas e nos índices disponíveis. Se elas refletem razoavelmente a realidade, ele faz as junções e executa as entradas da cláusula where na ordem que for melhor - geralmente as misturando, então faz um pouco disso, depois um pouco daquilo, e volta à primeira parte etc.
Como ver o que o otimizador fez
Você não pode ver o SQL no qual o PostgreSQL otimiza sua consulta, porque ele converte o SQL em uma representação interna da árvore de consultas e modifica isso. Você pode despejar o plano de consulta e compará-lo com outras consultas.
Não há como "separar" esse plano de consulta ou a árvore do plano interno de volta ao SQL.
http://explain.depesz.com/ possui um assistente de plano de consulta decente. Se você é totalmente novo em planos de consulta, etc. (nesse caso, estou surpreso por você ter chegado tão longe neste post), o PgAdmin possui um visualizador de plano de consulta gráfico que fornece muito menos informações, mas é mais simples.
Leitura relacionada:
Os recursos de empilhamento / retirada e nivelamento continuam a melhorar a cada versão . O PostgreSQL geralmente está certo sobre as decisões de pull-up / push-down / flattening, mas nem sempre, então ocasionalmente você precisa (ab) usar um CTE ou o OFFSET 0
hack. Se você encontrar esse caso, relate um erro do planejador de consultas.
Se você está realmente interessado, também pode usar a debug_print_plans
opção para ver o plano de consulta bruto, mas prometo que não deseja ler isso. Sério.