Suponiendo relativamente pocos filas en options
para muchas filas en records
.
Por lo general, tendría una tabla de búsqueda options
al que se hace referencia desde records.option_id
, idealmente con una restricción de clave externa. Si no lo hace, le sugiero que cree uno para hacer cumplir la integridad referencial:
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;
Entonces ya no hay necesidad de emular un escaneo de índice suelto y esto se vuelve muy simple y rápido . Las subconsultas correlacionadas pueden usar un índice simple en (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;
Esto incluye opciones que no coinciden en la tabla records
. Obtiene NULL para max_id
y puede eliminar fácilmente esas filas en un SELECT
externo si es necesario.
O (mismo resultado):
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;
Puede ser un poco más rápido. La subconsulta utiliza el orden de clasificación DESC NULLS LAST
- igual que la función agregada max()
que ignora los valores NULL. Ordenando solo DESC
tendría NULL primero:
- ¿Por qué los valores NULL aparecen primero cuando se solicita DESC en una consulta de PostgreSQL?
El índice perfecto para esto:
CREATE INDEX on records (option_id, id DESC NULLS LAST);
El orden de clasificación del índice no importa mucho mientras las columnas están definidas NOT NULL
.
Todavía puede haber un escaneo secuencial en la tabla pequeña options
, esa es la forma más rápida de obtener todas las filas. El ORDER BY
puede generar un escaneo de índice (solo) para obtener filas preordenadas.
La tabla grande records
solo se accede a través del escaneo de índice (mapa de bits) o, si es posible, escaneo de solo índice .
db<>violín aquí - mostrando dos escaneos de solo índice para el caso simple
Sqlfiddle antiguo
O usa LATERAL
se une para un efecto similar en Postgres 9.3+:
- Optimizar la consulta GROUP BY para recuperar la fila más reciente por usuario