MS-Office-Forum

MS-Office-Forum (https://www.ms-office-forum.net/forum/index.php)
-   Microsoft Access - Code Archiv (https://www.ms-office-forum.net/forum/forumdisplay.php?f=78)
-   -   SQL ist leicht (11) - Reihenfolge der Abfrageabarbeitung (https://www.ms-office-forum.net/forum/showthread.php?t=353639)

ebs17 10.08.2018 21:41

SQL ist leicht (11) - Reihenfolge der Abfrageabarbeitung
 
Zu wissen, was passiert bei so einer Abfrage, ist hilfreich wenn nicht gar notwendig, um funktionierende Anweisungen schreiben zu können, umso mehr, wenn eine Anweisung das machen soll, was man sich selber als Arbeitsablauf vorstellt. Im folgenden Text wird als Abfrage eine Auswahlabfrage verstanden, wobei aber eine Auswahlabfrage unmittelbar auch in Anfügeabfragen, Tabellenerstellungsabfragen und Kreuztabellenabfragen und spätestens als Unterabfrage auch in Aktualisierungsabfragen wiederzufinden ist.

Das Wichtige zuerst: Eine Abfrageanweisung wird nicht von vorne nach hinten oder von oben nach unten ausgeführt, wie man das von prozeduralen Sprachen wie VB(A), Java, Perl, C# u.v.a. kennt und erwartet. Ein zentrales Merkmal von SQL ist, dass nicht gesagt wird, wie etwas gemacht werden soll, sondern dass nur mitgeteilt wird, was zu tun sei. SQL wird deshalb als eine Sprache der vierten Generation klassifiziert. Diese Beschreibung, was zu tun ist, wird letztlich durch den SQL-Optimierer in einen Ausführungsplan überführt, und genau dieser kommt dann nachfolgend zur Anwendung.
Aber zur Orientierung kann man sich folgendes Beispiel anschauen, das schon mal ein paar Einzelheiten enthält:
Code:

SELECT
  X.FeldA,
  X.FeldB * 1 AS B,
  COUNT(X.FeldC) AS CC
FROM
  TabelleX AS X
      INNER JOIN TabelleY AS Y
      ON X.ID = Y.ID
WHERE
  X.FeldA = 'xyz'
GROUP BY
  X.FeldA,
  X.FeldB
HAVING
  COUNT(X.FeldC) > 3
ORDER BY
  X.FeldA

Reihenfolge der Abarbeitung:

1. Schritt: FROM-Teil
Es ist sinnvoll, mit dem FROM-Abschnitt zu beginnen, denn zuerst muss geprüft werden, ob die aufgeführten Tabellen und deren Felder zum Zeitpunkt der Abfrageausführung zugreifbar sind. Eine umbenannte Tabelle, ein verschobenes Backend oder eine Netzwerkunterbrechung wären hinreichende Gründe für einen Abbruch der Verarbeitung.
Nunmehr können Daten geladen werden.

2. Schritt: FROM- und WHERE-Teil
Verknüpfungen in JOIN's und Verknüpfungen und Filterungen im WHERE-Bereich sind erst einmal gleichrangig.
Code:

SELECT A.X, B.Y FROM A INNER JOIN B ON A.ID = B.ID

SELECT A.X, B.Y FROM A, B WHERE A.ID = B.ID

Diese Anweisungen sind in Ausführung und Ergebnis identisch, trotz der unterschiedlichen Formulierung. Das wird für manchen überraschend sein.
Bei mehr als einem Kriterium oder dann auch zusätzlichen Filtern bestimmt der SQL-Optimierer deren Abarbeitungsreihenfolge aus verschiedenen Parametern heraus (Indizierung, Tabellenstatistiken ...). Dessen Arbeitsweise kann man nicht eindeutig vorhersagen. Man kann aber nachträglich im Ablaufplan nachvollziehen, was der SQL-Optimierer ausführt.

3. Schritt: Gruppieren und Aggregation, GROUP BY-Abschnitt
Hier sollte am Rande bekannt sein, dass alle Felder im SELECT-Teil entweder im GROUP BY-Abschnitt enthalten sein müssen oder zu aggregieren sind (Bildung von Summen, Anzahlen, Durchschnitten, Maxima, Minima) oder einfach einen konstanten Inhalt aufweisen. Berechnete Ausdrücke aus solchen Feldern sind auch möglich.

4.Schritt: HAVING-Teil (noch einmal filtern)
WHERE vs. HAVING: WHERE filtert vor der Gruppierung, HAVING nach der Gruppierung. Wenn man sich vor Augen hält, dass Gruppieren eine aufwändige Operation ist (aufwändiger als Filtern), ist es leicht nachvollziehbar, dass man Datenmengen erst verkleinert und dann erst gruppiert (sofern man effizient arbeiten will).
Unter dem Strich würde man HAVING nur auf Aggregate (Summen, Anzahlen, Mittel-, Maximal-, Minimalwerte) anwenden. Alles andere ist "schief".

5. Schritt: Sortieren (ORDER BY) und SELECT-Teil (Berechnungen in Spalten)
Die genaue Abgrenzung der beiden Vorgänge ist schwierig.
Code:

ORDER BY FeldA * FeldC, FeldA, FeldC, FeldB

ORDER BY 4, 1, 3, 2

Die zweite Zeile zeigt eine Alternative, wie man für eine Sortierung statt der Feldnamen oder Berechnungsausdrücke die Nummern der Spalten im SELECT-Teil (mit 1 von links beginnend) einsetzen kann. Das kürzt die Länge der SQL-Anweisung, senkt aber auch etwas die Codelesbarkeit.

6. Schritt: SELECT-Teil (Rename, Neunamensgebung)
Jetzt wird die Ausgabe des Abfrageergebnisses vorbereitet. Im Besonderen werden die angewiesenen Spaltenaliase, die in Folge als Feldnamen nach außen wirken, gesetzt.


Was kann man daraus mal schnell ableiten?

1) Beginnen wir mit dem 6.Schritt, der Neunamensgebung von Spalten. Da diese als allerletzter Schritt erfolgt, dürfte verständlich werden, dass ein solcher Name beim Filtern, Gruppieren und Sortieren noch unbekannt ist und daher bei Verwendung eine Parameterrückfrage oder einen Fehler nach sich zieht. Dort muss also statt des Spaltenaliases der komplette zugehörige Berechnungsausdruck verwendet werden (ohne den Alias).

2) Befindet sich im FROM-Teil eine Unterabfrage oder gespeicherte Abfrage, wird diese zum Laden ausgeführt, also auch vor der aufrufenden Hauptabfrage. Möchte man also sicherstellen, dass bestimmte Filterungen zuerst ausgeführt werden, legt man sie in eine Unterabfrage des FROM-Abschnittes.

3) In Datenbankverarbeitungen hat man es sehr schnell mit sehr großen Datenmengen zu tun. Große Menge => viel benötigte Zeit. Das leuchtet sicher ein. Es gilt aber auch: Eine einfachere Aufgabe ist schneller erledigt als eine aufwändigere Aufgabe. So hat ein Filtern eines Feldes auf einen konstanten Wert (Parameter) ein kleineres Gewicht als Operationen, wo alle Schlüssel der einen Tabelle jeweils mit allen anderen Schlüsseln der gleichen Tabelle (Gruppieren) bzw. mit allen Schlüsseln der zweiten Tabelle (Verknüpfung) verglichen werden müssen.
Da ist es als Stilmittel für eine gute Performance naheliegend, erst zu filtern (wo es schon möglich ist) und so Datenmengen frühestmöglich zu reduzieren, ehe dann die aufwändigeren Operationen folgen. In Umsetzung dessen kommt man dann wieder auf Unterabfragen statt Tabellen.

4) Will man die Logik einer bestehenden Abfrage verstehen, liest man so, wie die Abfrage arbeitet. Man beginnt also mit dem FROM-Abschnitt. Sind dort Unterabfragen enthalten, geht man diese Ebene tiefer und schaut, wo kommen dort die Daten her. Das wird man wiederholen können, bis man auf die Tabellen trifft, die dann wirklich Felder mit Realdaten enthalten. Somit liest man eine Abfrage von innen nach außen. Am Ende merkt man: Ach, das ist ja ganz leicht ...


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:07 Uhr.

Powered by: vBulletin Version 3.6.2 (Deutsch)
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.