From: Moritz Bunkus Date: Mon, 26 Aug 2019 09:36:36 +0000 (+0200) Subject: SelfTest: Geschwindigkeitssteigerung durch »NOT EXISTS« anstelle von »NOT IN« X-Git-Tag: release-3.5.6.1~507 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=644b730bf07a0187ea05439bfd36b4e75fad2a3d;p=kivitendo-erp.git 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. --- diff --git a/SL/BackgroundJob/SelfTest/Transactions.pm b/SL/BackgroundJob/SelfTest/Transactions.pm index 3fbc0d14e..3eeb57f09 100644 --- a/SL/BackgroundJob/SelfTest/Transactions.pm +++ b/SL/BackgroundJob/SelfTest/Transactions.pm @@ -631,7 +631,7 @@ sub check_orphaned_reconciliated_links { my $query = qq| SELECT purpose from bank_transactions WHERE cleared is true - AND id not in (SELECT bank_transaction_id from reconciliation_links) + AND NOT EXISTS (SELECT bank_transaction_id from reconciliation_links WHERE bank_transaction_id = bank_transactions.id) AND transdate >= ? AND transdate <= ?|; my $bt_cleared_no_link = selectall_hashref_query($::form, $self->dbh, $query, $self->fromdate, $self->todate); @@ -681,7 +681,7 @@ sub check_orphaned_bank_transaction_acc_trans_links { my $query = qq| SELECT purpose from bank_transactions WHERE invoice_amount <> 0 - AND id not in (SELECT bank_transaction_id from bank_transaction_acc_trans) + AND NOT EXISTS (SELECT bank_transaction_id FROM bank_transaction_acc_trans WHERE bank_transaction_id = bank_transactions.id) AND itime > (SELECT min(itime) from bank_transaction_acc_trans) AND transdate >= ? AND transdate <= ?|; @@ -701,7 +701,7 @@ sub check_orphaned_bank_transaction_acc_trans_links { SELECT purpose from bank_transactions WHERE id in (SELECT bank_transaction_id from bank_transaction_acc_trans - where acc_trans_id NOT IN (select acc_trans_id from acc_trans) + 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) AND transdate >= ? AND transdate <= ?)|; my $bt_assigned_no_acc_trans = selectall_hashref_query($::form, $self->dbh, $query, $self->fromdate, $self->todate);