Lors de la récupération de toutes ou de la plupart des lignes d'une table, le moyen le plus rapide pour ce type de requête consiste généralement à agréger/désambiguïser d'abord et rejoignez plus tard :
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;
Plus il y a de lignes dans meta par ligne dans products , plus l'impact sur les performances est important.
Bien sûr, vous voudrez ajouter un ORDER BY clause dans la sous-requête définit quel ligne à sélectionner dans chaque ensemble de la sous-requête. @Craig et @Clodoaldo vous en ont déjà parlé. Je retourne le meta ligne avec le id le plus élevé .
Violon SQL.
Détails pour DISTINCT ON :
- Sélectionner la première ligne de chaque groupe GROUP BY ?
Optimiser les performances
Pourtant, ce n'est pas toujours la solution la plus rapide. Selon la distribution des données, il existe divers autres styles de requête. Pour ce cas simple impliquant une autre jointure, celle-ci s'est exécutée considérablement plus rapidement dans un test avec de grandes tables :
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;
Si vous n'utilisez pas l'id non descriptif en tant que noms de colonnes, nous ne rencontrerions pas de collisions de noms et pourrions simplement écrire SELECT p.*, m.* . (Je jamais utiliser id comme nom de colonne.)
Si la performance est votre exigence primordiale, envisagez d'autres options :
- une
MATERIALIZED VIEWavec des données pré-agrégées demeta, si vos données ne changent pas (beaucoup). - un CTE récursif émulant un balayage d'index lâche pour un gros
metatable avec beaucoup lignes par produit (relativement peu deproduct_iddistincts ).
C'est la seule façon que je connaisse d'utiliser un index pour une requête DISTINCT sur toute la table.