Ein häufiger
Irrglaube ist, dass man Datenbankabfragen allein durch kleine magische
Anpassungen an der SQL-Abfrage selbst um ein Vielfaches schneller machen kann.
Natürlich kann man hier durch gewisse Kniffe ein wenig nachhelfen; die
eigentliche Datenbankoptimierung beginnt allerdings wesentlich früher, nicht
erst bei den Abfragen.
Die
Optimierung beginnt tatsächlich bei der optimalen Nutzung der pages, der
Speichereinheiten der Datenbank. Je mehr pages durchsucht werden müssen,
desto länger dauert die Abfrage. Je ungünstiger der zur Verfügung stehende
Platz genutzt wird, desto mehr Seiten werden benötigt und müssen durchsucht
werden und desto länger dauert die Abfrage.
Also sehen
wir uns einmal die Architektur der Datenbank etwas genauer an.
Die
grundlegende Speichereinheit einer Datenbank ist eine page (Seite). Auf
einer solchen Seite befinden sich zum Großteil die eigentlichen, in der
Datenbank abgespeicherten Informationen; um diese Informationen aber effizient
finden zu können, bedarf es auch weiterer, sogenannter Metainformationen.
Diese
Metainformationen kann man sich vorstellen wie den Index in einem Lexikon;
Indizes in Datenbanken funktionieren sehr ähnlich. Man bekommt einen Verweis
darauf, wo sich der gesuchte Fachbegriff befindet, und kann direkt zur
entsprechenden Seite blättern, ohne das gesamte Lexikon lesen zu müssen. Auch
Indizes in der Datenbank ermöglichen uns ein schnelleres Finden von
Informationen durch Verweise, wo die Daten abgespeichert sind – und auch diese
zusätzliche Information muss irgendwo abgespeichert werden.
Die
Metadaten werden noch einmal weiter untergliedert, abhängig davon, um welche
Art von Information es sich handelt (beispielsweise Indexeinträge, oder eine
Information, wieviel freier Speicherplatz noch vorhanden ist).
Eine page
besteht aus einem page header, den eigentlichen Daten und dem row
offset.

Im Header
finden sich z.B. die Informationen dazu, welche Art von Daten hier gespeichert
wird und welche Indizes verwendet werden (Index ID).
Im
Row-Offset befindet sich die Information, welche Information in welcher Zeile
zu finden ist (wieder vergleichbar mit dem Index im Lexikon), was ein
schnelleres Auffinden von Daten ermöglicht. Die Offset-Informationen am Ende
jeder Seite sind in umgekehrter Reihenfolge zu den Zeilen abgespeichert.
Insgesamt
besteht eine Seite (page) aus 8192 Byte. Davon entfallen 96 Byte auf den
page header, maximal 8060 Byte auf eine einzelne Zeile. Ein row
offset Eintrag belegt 2 Byte. Für jede Zeile kommen noch einmal 7 Byte an
Overhead hinzu.

Eine Zeile
beansprucht also den Platz für den eigentlichen Eintrag (abhängig von Datentyp
und Anzahl Zeichen) + 7 Byte an overhead + 2 Byte für row offset.
Daraus ergibt sich, wie viele Zeilen auf einer Seite Platz haben.
Je besser
die Seiten befüllt sind, desto weniger Seiten müssen insgesamt für das Ergebnis
durchsucht werden. Wäre ein einziger Datensatz 4100 Byte lang, würde nur ein
einziger Eintrag auf eine Seite passen (zwei würden mit 8200 Byte den Speicherplatz
der Seite überschreiten)! Und diese wäre noch dazu nur knapp über die Hälfte
befüllt. Wir würden unsinnig viel Speicherplatz verbrauchen und die Abfragen
wären unerträglich langsam.
Genaugenommen
fängt die Optimierung also bei intelligent gewählten Datentypen an!
8 Seiten
(pages) ergeben einen sogenannten Block (engl.: Extent), eine Einheit zur Verwaltung des Speicherplatzes.
Bei rund 8 KB pro page ergibt das also 64 KB pro Block. Das macht 16
Blöcke pro 1 MB.
Solche und
weitere Themen im Bereich der Datenbankoptimierung gibt es auch in unserem zweitägigen
Kurs SQL Server – Abfragen und Indizes optimieren.