sql >> Database teknologi >  >> RDS >> PostgreSQL

Optimer gruppevis maksimal forespørgsel

Forudsat relativt rækker i options for mange rækker i records .

Typisk vil du have en opslagstabel options der henvises til fra records.option_id , ideelt set med en fremmednøglebegrænsning. Hvis du ikke gør det, foreslår jeg at oprette en for at håndhæve referentiel integritet:

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;

Så er der ingen grund til at efterligne en løs indeksscanning længere, og dette bliver meget enkelt og hurtigt . Korrelerede underforespørgsler kan bruge et almindeligt indeks på (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;

Dette inkluderer muligheder uden match i tabel records . Du får NULL for max_id og du kan nemt fjerne sådanne rækker i en ydre SELECT hvis det er nødvendigt.

Eller (samme resultat):

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;

Kan være lidt hurtigere. Underforespørgslen bruger sorteringsrækkefølgen DESC NULLS LAST - samme som den samlede funktion max() som ignorerer NULL-værdier. Sorterer kun DESC ville have NULL først:

  • Hvorfor kommer NULL-værdier først, når du bestiller DESC i en PostgreSQL-forespørgsel?

Det perfekte indeks til dette:

CREATE INDEX on records (option_id, id DESC NULLS LAST);

Indekssorteringsrækkefølgen betyder ikke meget, mens kolonner er defineret NOT NULL .

Der kan stadig være en sekventiel scanning på den lille tabel options , det er bare den hurtigste måde at hente alle rækker på. ORDER BY kan indsætte en (kun) indeksscanning for at hente forudsorterede rækker.
Den store tabel records er kun tilgængelig via (bitmap) indeksscanning eller, hvis det er muligt, kun indeksscanning .

db<>spil her - viser kun to indeksscanninger for den simple sag
Gamle sqlfiddle

Eller brug LATERAL slutter sig til en lignende effekt i Postgres 9.3+:

  • Optimer GROUP BY-forespørgsel for at hente seneste række pr. bruger


  1. Nedetid og Hotpatch-anvendelsestilstand i adop R12.2

  2. Når du åbner en orakelforbindelse, er forbindelsesobjektet nul

  3. Hvordan arbejder jeg med høj præcision decimaler i PHP

  4. Postgresql Drop View