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

Como faço para escrever uma junção com esses critérios de correspondência incomuns?

Índices


Crie índices em x.id e y.id - que você provavelmente já tem se essas forem suas chaves primárias.
Um índice de várias colunas também pode ajudar, especialmente com scans somente de índice na página 9.2+:
CREATE INDEX y_mult_idx ON y (id DESC, val)

No entanto, em meus testes, esse índice não foi usado inicialmente. Tive que adicionar (de outra forma inútil) val para ORDER BY para convencer o planejador de consultas de que a ordem de classificação corresponde. Consulte a consulta 3 .

O índice faz pouca diferença nesta configuração sintética. Mas para tabelas com mais colunas, recuperando val da tabela torna-se cada vez mais caro, tornando o índice de "cobertura" mais atrativo.

Consultas

1) Simples

SELECT DISTINCT ON (x.id)
       x.id, y.val
FROM   x
JOIN   y ON y.id <= x.id
ORDER  BY x.id, y.id DESC;

SQL Fiddle.

Mais explicações para a técnica com DISTINCT nesta resposta relacionada:

Fiz alguns testes porque tinha minhas suspeitas de que a primeira consulta não seria bem dimensionada. É rápido com uma mesa pequena, mas não é bom com mesas maiores. O Postgres não otimiza o plano e começa com uma junção cruzada (limitada), com um custo de O(N²) .

2) Rápido


Esta consulta ainda é bastante simples e escala excelentemente:
SELECT x.id, y.val
FROM   x
JOIN  (SELECT *, lead(id, 1, 2147483647) OVER (ORDER BY id) AS next_id FROM y) y
       ON  x.id >= y.id
       AND x.id <  y.next_id
ORDER  BY 1;

A função de janela lead() é instrumental. Eu uso a opção de fornecer um padrão para cobrir a caixa de canto da última linha:2147483647 é o maior inteiro possível . Adapte-se ao seu tipo de dados.

3) Muito simples e quase tão rápido

SELECT x.id
     ,(SELECT val FROM y WHERE id <= x.id ORDER BY id DESC, val LIMIT 1) AS val
FROM   x;

Normalmente, subconsultas correlacionadas tendem a ser lentos. Mas este pode apenas escolher um valor do índice (de cobertura) e é tão simples que pode competir.

O ORDER BY adicional item val (ênfase em negrito) parece inútil. Mas adicioná-lo convence o planejador de consultas de que não há problema em usar o índice de várias colunas y_mult_idx de cima, porque a ordem de classificação corresponde. Note o

no EXPLAIN resultado.

Caso de teste


Após um debate animado e várias atualizações, coletei todas as consultas postadas até agora e fiz um caso de teste para uma visão geral rápida. Eu uso apenas 1000 linhas para que o SQLfiddle não atinja o tempo limite com as consultas mais lentas. Mas os 4 primeiros (Erwin 2, Clodoaldo, a_horse, Erwin 3) escalam linearmente em todos os meus testes locais. Atualizado mais uma vez para incluir minha última adição, melhorar o formato e ordenar por desempenho agora:

Big SQL Fiddle comparando o desempenho.