Projekt

Allgemein

Profil

« Zurück | Weiter » 

Revision 644b730b

Von Moritz Bunkus vor mehr als 5 Jahren hinzugefügt

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.

Unterschiede anzeigen:

SL/BackgroundJob/SelfTest/Transactions.pm
631 631
  my $query = qq|
632 632
          SELECT purpose from bank_transactions
633 633
          WHERE cleared is true
634
          AND id not in (SELECT bank_transaction_id from reconciliation_links)
634
          AND NOT EXISTS (SELECT bank_transaction_id from reconciliation_links WHERE bank_transaction_id = bank_transactions.id)
635 635
          AND transdate >= ? AND transdate <= ?|;
636 636

  
637 637
  my $bt_cleared_no_link = selectall_hashref_query($::form, $self->dbh, $query, $self->fromdate, $self->todate);
......
681 681
  my $query = qq|
682 682
          SELECT purpose from bank_transactions
683 683
          WHERE invoice_amount <> 0
684
          AND id not in (SELECT bank_transaction_id from bank_transaction_acc_trans)
684
          AND NOT EXISTS (SELECT bank_transaction_id FROM bank_transaction_acc_trans WHERE bank_transaction_id = bank_transactions.id)
685 685
          AND itime > (SELECT min(itime) from bank_transaction_acc_trans)
686 686
          AND transdate >= ? AND transdate <= ?|;
687 687

  
......
701 701
          SELECT purpose from bank_transactions
702 702
          WHERE id in
703 703
          (SELECT bank_transaction_id from bank_transaction_acc_trans
704
           where acc_trans_id NOT IN (select acc_trans_id from acc_trans)
704
           WHERE NOT EXISTS (SELECT acc_trans.acc_trans_id FROM acc_trans WHERE acc_trans.acc_trans_id = bank_transaction_acc_trans.acc_trans_id)
705 705
           AND transdate >= ? AND transdate <= ?)|;
706 706

  
707 707
  my $bt_assigned_no_acc_trans = selectall_hashref_query($::form, $self->dbh, $query, $self->fromdate, $self->todate);

Auch abrufbar als: Unified diff