PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

Impacto no desempenho da visualização na função agregada versus limitação do conjunto de resultados

Consultas não estritamente equivalentes


Para deixar o contexto claro:
  • max(id) exclui NULL valores. Mas ORDER BY ... LIMIT 1 não.
  • NULL os valores são classificados por último em ordem crescente e primeiro em ordem decrescente. Portanto, um Index Scan Backward pode não encontrar o maior valor (de acordo com max() ) primeiro, mas qualquer número de NULL valores.

O equivalente formal de:
SELECT max(id) FROM testview;

não é:
SELECT id FROM testview ORDER BY id DESC LIMIT 1;

mas:
SELECT id FROM testview ORDER BY id DESC NULLS LAST LIMIT 1;

A última consulta não obtém o plano de consulta rápida. Mas seria com um índice com ordem de classificação correspondente:(id DESC NULLS LAST) .

Isso é diferente para as funções agregadas min() e max() . Esses recebem um plano rápido ao segmentar a tabela test1 diretamente usando o índice PK simples em (id) . Mas não quando baseado na visão (ou na consulta de junção subjacente diretamente - a visão não é o bloqueador). Um índice classificando valores NULL no lugar certo quase não tem efeito.

Nós saiba que id nesta consulta nunca pode ser NULL . A coluna é definida NOT NULL . E a junção na visão é efetivamente um INNER JOIN que não pode introduzir NULL valores para id .
Nós também saiba que o índice em test.id não pode conter valores NULL.
Mas o planejador de consultas Postgres não é uma IA. (Nem tenta ser, isso pode sair do controle rapidamente.) Vejo duas deficiências :
  • min() e max() obter o plano rápido apenas ao direcionar a tabela, independentemente da ordem de classificação do índice, uma condição de índice é adicionada:Index Cond: (id IS NOT NULL)
  • ORDER BY ... LIMIT 1 obtém o plano rápido apenas com a ordem de classificação do índice exatamente correspondente.

Não tenho certeza se isso pode ser melhorado (facilmente).

db<>fiddle aqui - demonstrando todos os itens acima

Índices


Este índice é completamente inútil:
CREATE INDEX ON "test" ("id");

O PK em test.id é implementado com um índice exclusivo na coluna, que já cobre tudo o que o índice adicional pode fazer por você.

Pode haver mais, esperando que a pergunta esclareça.

Caso de teste distorcido


O caso de teste está muito longe do caso de uso real para ser significativo.

Na configuração do teste, cada tabela tem 100 mil linhas, não há garantia de que todos os valores em joincol tem uma correspondência do outro lado e ambas as colunas podem ser NULL

Seu caso real tem 10 milhões de linhas em table1 e <100 linhas em table2 , cada valor em table1.joincol tem uma correspondência em table2.joincol , ambos são definidos NOT NULL e table2.joincol é único. Um relacionamento clássico de um para muitos. Deve haver um UNIQUE restrição em table2.joincol e uma restrição FK t1.joincol --> t2.joincol .

Mas isso é atualmente tudo distorcido na questão. Aguardando até que seja limpo.