Ao recuperar todas ou a maioria das linhas de uma tabela, a maneira mais rápida para esse tipo de consulta normalmente é agregar/desambiguar primeiro e participe mais tarde :
SELECT *
FROM products p
JOIN (
SELECT DISTINCT ON (product_id) *
FROM meta
ORDER BY product_id, id DESC
) m ON m.product_id = p.id;
Quanto mais linhas em
meta
por linha em products
, maior o impacto no desempenho. Claro, você vai querer adicionar um
ORDER BY
cláusula na subconsulta define qual linha para escolher cada conjunto na subconsulta. @Craig e @Clodoaldo já te falaram sobre isso. Estou retornando o meta
linha com o id
mais alto . violino SQL.
Detalhes para
DISTINCT ON
:- Selecionar a primeira linha em cada grupo GROUP BY?
Otimize o desempenho
Ainda assim, esta nem sempre é a solução mais rápida. Dependendo da distribuição de dados, existem vários outros estilos de consulta. Para este caso simples envolvendo outra junção, esta correu consideravelmente mais rápido em um teste com grandes tabelas:
SELECT p.*, sub.meta_id, m.product_id, m.price, m.flag
FROM (
SELECT product_id, max(id) AS meta_id
FROM meta
GROUP BY 1
) sub
JOIN meta m ON m.id = sub.meta_id
JOIN products p ON p.id = sub.product_id;
Se você não usar o
id
não descritivo como nomes de colunas, não teríamos colisões de nomenclatura e poderíamos simplesmente escrever SELECT p.*, m.*
. (Eu nunca use id
como nome da coluna.) Se o desempenho for seu requisito primordial, considere mais opções:
- uma
MATERIALIZED VIEW
com dados pré-agregados demeta
, se seus dados não mudarem (muito). - um CTE recursivo emulando uma varredura de índice solto para um grande
meta
tabela com muitos linhas por produto (relativamente poucosproduct_id
distintos ).
Esta é a única maneira que conheço de usar um índice para uma consulta DISTINCT em toda a tabela.