Rolf B: mysql, Query optimieren

Beitrag lesen

Hallo Jörg,

(1) GROUP BY und SUM

Du summierst nur einen Wert aus den Bruttozahlungen und damit ist es der Overkill, erstmal einen riesigen Join aufzuspannen und den mit GROUP BY wieder einzudampfen. Das geht besser. Dazu gleich, erstmal eine Predigt.

Du begehst mit deinem GROUP BY (wieder einmal?) den heißgeliebtesten Fehler aller MYSQL Nutzer. Korrektes SQL muss alle Spalten im Group By auflisten, die nicht aggregiert werden. Jede SQL Datenbank außer MySQL und seiner Stiefschwester MariaDB wirft einen Fehler, wenn man das missachtet, aber nur weil MySQL nicht meckert, ist es nicht automatisch gut.

Es ist deshalb falsch, weil für Spalten, die im GROUP BY nicht stehen und nicht aggregiert werden, nicht festgelegt ist, aus welcher der aggregierten Rows ihr Wert stammt.

Wenn das die Daten sind:

ID  Name   Wert
 1  Hugo     5
 1  Otto     6
 2  Paul     3
 3  Lisa     1
 3  Lara     9

dann würde das Statement

SELECT ID, Name, SUM(Wert)
FROM tabelle
GROUP BY ID

von MySQL und MariaDB ausgeführt, aber jede ordentliche Datenbank würde es Dir auf die Füße kotzen. Weil Name nicht im GROUP BY steht.

Ob dein MySQL nämlich

ID  Name   Wert
 1  Hugo    11
 2  Paul     3
 3  Lisa    10

oder

ID  Name   Wert
 1  Otto    11
 2  Paul     3
 3  Lara    10

liefert, ist undefiniert!!!1!1!!!elf!!1!

In deinem Fall gibt es einen einfachen Ausweg, weil Du nur eine Spalte summierst und die ze Tabelle nur für diesen Zweck joinst.

Du kannst diesen JOIN sowie den GROUP BY weglassen und statt dessen diesen Subselect verwenden:

...
k.kdel,
(SELECT SUM(ze.Bruttozahlung) 
     FROM _table_zahlungseingang ze 
     WHERE ze.RechnungenID = r.RechnungenID) as BruttoSumme,
rz.GesamtRetoure
...

Berechneten Spalten einen Aliasnamen zu geben ist übrigens guter Brauch, dann kannst Du sie nachher im PHP auch namentlich verwenden und musst nicht mit Spaltennummern arbeiten.

(2) _table_mahnungen

Was ich nicht verstehe, ist der JOIN der Mahnungen.

LEFT JOIN _table_mahnungen m
    ON ( r.RechnungenID = m.RechnungenID AND m.aktiv = 1)
      AND m.RechnungenID = (SELECT MAX(tmp.RechnungenID)
                            FROM _table_mahnungen tmp
                            WHERE tmp.RechnungenID = r.RechnungenID AND m.aktiv = 1)

MAX(tmp.RechnungenID) muss immer gleich r.RechnungenID sein, weil andere Rows nicht selektiert werden. Es könnte höchstens sein, dass _table_mahnungen keinen einzigen Satz zu dieser RechnungenID enthält, aber den Fall fängt schon die erste Join-Bedingung, vor dem AND, ab. Der ganze AND-Teil erscheint mir nutzlos und der Subselect darin dann auch.

(3) _table_berechnungen

Ob der LEFT JOIN der Tabelle _table_berechnungen nötig ist, weißt nur Du. Dein gezeigtes SQL verwendet keine Spalte aus dieser Tabelle.

Damit hast Du schonmal eine Menge Arbeit, hoffentlich nötzt se was.

Rolf

--
sumpsi - posui - obstruxi