SelfTest: Geschwindigkeitssteigerung durch »NOT EXISTS« anstelle von »NOT IN«
authorMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 26 Aug 2019 09:36:36 +0000 (11:36 +0200)
committerMoritz Bunkus <m.bunkus@linet-services.de>
Mon, 26 Aug 2019 09:41:26 +0000 (11:41 +0200)
commit644b730bf07a0187ea05439bfd36b4e75fad2a3d
tree222b064ff3254881537eb6c96c789440a21bc94f
parentf5ced930f00d537a86e87b57b6786f859e0ff759
SelfTest: Geschwindigkeitssteigerung durch »NOT EXISTS« anstelle von »NOT IN«

Nicht ganz frische PostgreSQL-Versionen (mindestens bis 9.6 inklusive)
optimieren »NOT IN«-mit-Subquery nicht automatisch und müssen daher
für jede Zeile des äußeren Selects einen linearen Scan auf die
Subquery-Tabelle machen.

Deutlich effektiver ist das in diesem Fall äquivalente »NOT
EXISTS«-mit-Subquery.

Beispiel: Namen aller Kunden, für die noch keine Rechnung geschrieben
wurde. Falsch mit »NOT IN«:

SELECT name
FROM customer
WHERE id NOT IN (
  SELECT customer_id
  FROM ar
);

Besser und semantisch äquivalent:

SELECT name
FROM customer
WHERE NOT EXISTS (
  SELECT customer_id
  FROM ar
  WHERE customer_id = customer.id
);

Geschwindigkeitssteigerung ist auch ein Euphemismus. Vor der Änderung
war der Selftest bei der LINET-Produktivdatenbank nicht in der Lage,
seine Tests innerhalb von drei Tagen auszuführen. Nach der Änderung
dauert der Selftest weniger als eine Minute.

Neure PostgreSQL-Versionen (z.B. v11) erkennen dieses Pattern
automatisch.
SL/BackgroundJob/SelfTest/Transactions.pm