\section{Relationale Operatoren} \subsection{Allgemein} Die grundsätzliche Aufgabe besteht darin die logischen Operatoren (SEL(),PROJ(),JOIN(),\ldots) durch \textbf{Planoperatoren} zu ersetzen.\\ \textbf{Teilaufgaben}: \begin{itemize} \item Erkennung gemeinsamer Teilbäume (notwendig: Zwischenspeicherung von Ergebnisrelation) \item {Bestimmung der Verknüpfungsreihenfolge bei Verbundoperationen: \begin{itemize} \item Ziel: minimale Kosten für die Operationsfolge \item Heuristik: Minimierung der Größe der Zwischenergebnisse, d.h. kleinsten Relationen immer zuerst verknüpfen \end{itemize} } \item Gruppierung von direkt benachbarten Operatoren zu einem einzelnen Planoperator (z.B. Verbund mit Selektion) \end{itemize} \subsection{Planoperatoren} SQL erlaubt Anfragen über k-Relationen: \begin{itemize} \item Ein Variablen Ausdrücke (eine Relation) \item Zwei Variablem AUsdrücke (zwei Relationen) \item k-Variablen Ausdrücke (zerlegt in Ein- und Zwei Variablen Ausdrücke) \end{itemize} \subsubsection{Selektion} \begin{itemize} \item Nutzung eines \textbf{Scan}-Operators\\ Definition von Start- und Stoppbedingungen sowie Suchargumenten \item Index Scan $\rightarrow$ Auswahl des kostengünstigsten Index \item Relationen Scan \end{itemize} \subsubsection{Projektion} \begin{itemize} \item meist in Kobination mit Verbund, Selektion und Sortierung \item auch als eigener Planoperator \end{itemize} \subsubsection{Sortierung} \begin{itemize} \item erforderlich bei \textbf{order by} \item beschleunigt ggf Joins \item Duplikateleminierung (\textbf{distinct}) \end{itemize} \subsubsection{Joins} Joins werden in \textbf{binäre} Verbunde gegliedert. Bei $n$ Verbunden sind $n!$ Reihenfolgen möglich. Die optimale Reihenfolge ist abhängig von \begin{itemize} \item Planoperatoren \item passenden Sortierordnungen \item Größe der Operanden usw \end{itemize} Verbundoperationen sind sehr häufig und auch teuer $\rightarrow$ Optimierung.\\ Typisch sind \textbf{Gleichverbunde}. Standartszenario für Verbunde: \begin{lstlisting} select * from R,S where R.VA $\Theta$ S.VA // Verbundpraedikat // $\Theta \in \{=, >, <, \neq, \geq, \leq\}$ and P(R.SA) // lokale Selektion and P(S.SA) // VA = Verbundattribut // SA = Selektionsattribut \end{lstlisting} \paragraph{Nested Loop Verbund} Annahmen:\\ Sätze in R und S sind nicht nach Verbundsattributen geordnet.\\ Es sind keine Indexstrukturen $I_R(VA)$ und $I_S(VA)$ vorhanden. \begin{lstlisting} Scan ueber $S$; //aeussere Schleife fuer jeden Satz s, fuer den $P(s.SA)$ gilt: Scan ueber $R$; //innere Schleife fuer jeden Satz r, fuer den P(r.SA) AND (r.VA $\Theta$ s.VA) gilt: uebernimm kombinierten SAtz (r,s) in das Ergebnis; \end{lstlisting} Komplexität: $\mathcal O(N^2)$ \paragraph{Sort-Merge Verbund} Zweiphasiger Algorithmus:\\ Phasen: \begin{enumerate} \item Sortierung von R und S nach R.VA und S.VA, dabei Eliminierung nicht benötigter Tupel (durch Prüfung von P(R.SA) oder P(S.SA)) \item schritthaltende Scans über R- und S-Relationen mit Durchführung des Verbundes bei r.VA=s.VA \end{enumerate} Komplexität: $\mathcal O(N \log N)$ \begin{figure}[H] \begin{center} \includegraphics[scale=0.7]{pics/merge_sort_join.png} \caption{Merge Sort Verbund} \end{center} \end{figure} \paragraph{Hash Verbund} Spezialisierung für \textbf{Gleichverbund}. Da der Hauptspeicher immer größer ist, lassen sich Zwischenergebnisse besser ausnutzen.\\ Idee: \begin{itemize} \item Tupel der einen Relation im HS ablegen, so dass sie über VerbundAttribut schnell gefunden werden können \item Tupel der anderen Relation sequenziell durchlaufen und mit Wert des VerbundAttributs die passenden Verbundpartner im HS aufsuchen \item Organisation der Tupel im HS über \textbf{Hashing} \end{itemize} Einfachster Fall: \textbf{Classic Hashing}:\\ Funktionsweise:\\ Äußere Schleife \begin{itemize} \item Abschnittweise lesen der kleineren Relation R \item Relation wird in $p$ Abschnitte aufgeteilt, die alle in HS passen \item Aufbau einer Hash Tabelle mit $\text{h}_\text{A}($r.VA$)$ \end{itemize} Innere Schleife \begin{itemize} \item Überprüfung für jeden Satz von S mit P(S.SA) $\rightarrow$ ebenfalls mit Hashing \item wenn sich Verbundpartner in dieser Adresse befindet, Durchführung des Verbundes \end{itemize} Komplexität: $\mathcal O(p \times N)$. Da Verbundpartner S $p$-mal gelesen werden muss. \begin{figure}[H] \begin{center} \includegraphics[scale=0.8]{pics/hash_join.png} \caption{Hash Verbund} \end{center} \end{figure} Problem ist, dass S $p$-mal durchlaufen werden muss. Daher die Idee S analog zu R zu partitionieren.\\ Stichwort Simple Hashing. \subsection{Anfrageoptimierung} Ziel:\\$\rightarrow$ Ermittlung des \textit{kostengünstigsten} Auswertungsweges Zentrales Problem: \begin{itemize} \item globales Optimieren hat hohe Komplexität (NP-Schwer zur Laufzeit) \item Einsatz von Heuristiken, da nicht alles nötige Wissen immer vorhanden ist \end{itemize} Optimierungsziel: \begin{itemize} \item Maximierung des Outputs bei gegeben Ressoucren \item Minimierung der Resourcennutzung \end{itemize} Die Wichtigsten Kostenarten sind: \begin{itemize} \item Berechnungskosten (CPU) \item I/O Kosten (Anzahl physischer Referenzen) \end{itemize} \subsubsection{Ausführungsplan} Ziel ist es eine möglichst guten Ausführungsbaum zu erstellen. Problematisch ist die riesige Anzahl an Möglichkeiten mit steigender Komplexität der Anfrage (z.B. Query mit 15 Verbunden $10^{70}$ Möglichkeiten).\\ Diese Vielfalt entsteht durch verschiedene Implementierungen der Planoperatoren und der Operationsreiehenfolgen. $\rightarrow$ \textbf{Ziel der Plangenerierung}: \begin{itemize} \item finden von Plänen gelingt immer schnell \item mit möglichst wenig generierten Plänen auskommen \end{itemize} Unterschiedliche Strategieklassen: \begin{itemize} \item voll enumerativ \item beschränkt enumerativ \item zufallsgesteuert \end{itemize} \paragraph{Kostenformeln} \begin{itemize} \item{ gewichtetes Ma"s für I/O und CPU Belastung:\\ C = \#physische-Seitenzugriffe + W $\times$ \#Aufrufe-des Zugriffsystems} \item{ CPU-bound : höherer I/O-, geringerer CPU Aufwand:\\ $\text{W}_{\text{CPU}}$ = \#Instr-pro-Aufruf-des-Zugriffsystems /\\ \#Instr-pro-I/O-Vorgang } \item{ I/O-bound : geringere I/O-, höherer CPU Aufwand:\\ $\text{W}_{\text{CPU}}$ = \#Instr-pro-Aufruf-des-Zugriffsystems /\\ (\#Instr-pro-I/O-Vorgang + Zugriffzeit $\times $ MIPS-Ratte) } \end{itemize} \paragraph{Selektivitätsanschätzung} Der \textbf{Selektivitätsfaktor} beschreibt den erwarteten Anteil an Tupeln, die ein Prädikat p erfüllen.\\ Diese Trefferate gibt auch an, inwiefern eine vorhandene Indexstruktur die Laufzeit reduzieren. \begin{figure}[H] \begin{center} \includegraphics[scale=1.0]{pics/trefferrate.png} \caption{Qualitatives Zugriffsdiagramm} \end{center} \end{figure} Nur bei sehr geringen Trefferraten lohnt sich ein Index Scan!