sql >> Base de Datos >  >> RDS >> PostgreSQL

Optimizar consulta máxima grupal

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