Supondo que relativamente poucos linhas em
options
para muitas linhas em records
. Normalmente, você teria uma pesquisa de tabela
options
que é referenciado em records.option_id
, de preferência com uma restrição de chave estrangeira. Se você não fizer isso, sugiro criar um para impor a integridade 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;
Então não há mais necessidade de emular uma varredura de índice solta e isso se torna muito simples e rápido . Subconsultas correlacionadas podem usar um índice simples em
(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;
Isso inclui opções sem correspondência na tabela
records
. Você recebe NULL para max_id
e você pode remover facilmente essas linhas em um SELECT
externo se necessário. Ou (mesmo 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;
Pode ser um pouco mais rápido. A subconsulta usa a ordem de classificação
DESC NULLS LAST
- igual à função agregada max()
que ignora valores NULL. Classificando apenas DESC
teria NULL primeiro:- Por que os valores NULL vêm primeiro ao ordenar DESC em uma consulta do PostgreSQL?
O índice perfeito para isso:
CREATE INDEX on records (option_id, id DESC NULLS LAST);
A ordem de classificação do índice não importa muito enquanto as colunas são definidas
NOT NULL
. Ainda pode haver uma varredura sequencial na pequena tabela
options
, essa é apenas a maneira mais rápida de buscar todas as linhas. O ORDER BY
pode trazer uma varredura de índice (somente) para buscar linhas pré-ordenadas.A grande tabela
records
só é acessado via varredura de índice (bitmap) ou, se possível, varredura somente de índice . db<>mexa aqui - mostrando duas varreduras somente de índice para o caso simples
Old sqlfiddle
Ou use
LATERAL
joins para um efeito semelhante no Postgres 9.3+:- Otimize a consulta GROUP BY para recuperar a última linha por usuário