En supposant relativement peu lignes dans options
pour plusieurs lignes dans records
.
Typiquement, vous auriez une recherche table options
qui est référencé à partir de records.option_id
, idéalement avec une contrainte de clé étrangère. Si ce n'est pas le cas, je vous suggère d'en créer un pour renforcer l'intégrité référentielle :
CREATE TABLE options (
option_id int PRIMARY KEY
, option text UNIQUE NOT NULL
);
INSERT INTO options
SELECT DISTINCT option_id, 'option' || option_id -- dummy option names
FROM records;
Ensuite, il n'est plus nécessaire d'émuler un balayage d'index lâche et cela devient très simple et rapide . Les sous-requêtes corrélées peuvent utiliser un index simple sur (option_id, id)
.
SELECT option_id, (SELECT max(id)
FROM records
WHERE option_id = o.option_id) AS max_id
FROM options o
ORDER BY 1;
Cela inclut les options sans correspondance dans la table records
. Vous obtenez NULL pour max_id
et vous pouvez facilement supprimer ces lignes dans un SELECT
externe si nécessaire.
Ou (même résultat) :
SELECT option_id, (SELECT id
FROM records
WHERE option_id = o.option_id
ORDER BY id DESC NULLS LAST
LIMIT 1) AS max_id
FROM options o
ORDER BY 1;
Peut être légèrement plus rapide. La sous-requête utilise l'ordre de tri DESC NULLS LAST
- identique à la fonction d'agrégation max()
qui ignore les valeurs NULL. Tri uniquement DESC
aurait NULL en premier :
- Pourquoi les valeurs NULL sont-elles prioritaires lors de l'ordre de DESC dans une requête PostgreSQL ?
L'index parfait pour cela :
CREATE INDEX on records (option_id, id DESC NULLS LAST);
L'ordre de tri de l'index n'a pas beaucoup d'importance tant que les colonnes sont définies NOT NULL
.
Il peut toujours y avoir un parcours séquentiel sur la petite table options
, c'est simplement le moyen le plus rapide de récupérer toutes les lignes. Le ORDER BY
peut apporter une analyse d'index (uniquement) pour récupérer des lignes pré-triées.
La grande table records
n'est accessible que par balayage d'index (bitmap) ou, si possible, balayage d'index uniquement .
db<>jouez ici - montrant deux analyses d'index uniquement pour le cas simple
Ancien sqlfiddle
Ou utilisez LATERAL
se joint pour un effet similaire dans Postgres 9.3+ :
- Optimiser la requête GROUP BY pour récupérer la dernière ligne par utilisateur