sql >> Database >  >> RDS >> PostgreSQL

Optimaliseer groepsgewijze maximale zoekopdracht

Ervan uitgaande dat relatief weinig rijen in options voor veel rijen in records .

Normaal gesproken zou u een tabel options . opzoeken waarnaar wordt verwezen vanuit records.option_id , idealiter met een externe sleutelbeperking. Als je dat niet doet, raad ik aan er een te maken om referentiële integriteit af te dwingen:

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;

Dan is het niet meer nodig om een ​​losse indexscan te emuleren en dit wordt heel eenvoudig en snel . Gecorreleerde subquery's kunnen een gewone index gebruiken op (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;

Dit omvat opties zonder overeenkomst in tabel records . Je krijgt NULL voor max_id en je kunt zulke rijen gemakkelijk verwijderen in een buitenste SELECT indien nodig.

Of (zelfde resultaat):

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;

Mag iets sneller. De subquery gebruikt de sorteervolgorde DESC NULLS LAST - hetzelfde als de verzamelfunctie max() die NULL-waarden negeert. Alleen DESC sorteren zou eerst NULL hebben:

  • Waarom komen NULL-waarden eerst bij het bestellen van DESC in een PostgreSQL-query?

De perfecte index hiervoor:

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

Index-sorteervolgorde maakt niet veel uit, terwijl kolommen zijn gedefinieerd NOT NULL .

Er kan nog steeds een sequentiële scan zijn op de kleine tafel options , dat is gewoon de snelste manier om alle rijen op te halen. De ORDER BY kan een (alleen) indexscan opleveren om voorgesorteerde rijen op te halen.
De grote tabel records is alleen toegankelijk via (bitmap) indexscan of, indien mogelijk, index-only scan .

db<>viool hier - toont twee alleen-index scans voor het eenvoudige geval
Oude sqlfiddle

Of gebruik LATERAL sluit zich aan voor een soortgelijk effect in Postgres 9.3+:

  • Optimaliseer de GROUP BY-query om de laatste rij per gebruiker op te halen


  1. TLS inschakelen in Oracle Apps R12.2

  2. Hoe u meer dan 1000 waarden in een Oracle IN-clausule plaatst?

  3. Oracle RAC VIP en ARP Primer

  4. Geaggregeerde functie in MySQL - lijst (zoals LISTAGG in Oracle)