Tuning von Datenbanken aus der Sicht des Programmierers - insbesondere SQL-Tuning
Blasius Lofi Dewanto
Institut für Wirtschaftsinformatik
Westfälische Wilhelms-Universität Münster
Grevener Str. 91, 48159 Münster
Zum Downloaden
ZIP Datei
Inhalt
Inhaltsverzeichnis

1 Einleitung

2 Tuning einer Datenbank aus der Sicht des Programmierers

2.1 SQL-Tuning
2.1.1 Wichtige Kriterien für die Optimierung
2.1.2 Der Optimizer
2.1.3 Tuning per Hand
2.1.4 Teilen des SQL-Statements
2.1.5 Die Reihenfolge der Tabellennamen
2.1.6 Die Reihenfolge der Kondition im WHERE-Statement
2.1.7 Optimierung des Zugriffs auf die Datenbank
2.1.8 DECODE-Statement
2.1.9 Weitere Tips zur Verbesserung der Performance
2.1.10 Nutzung von Indexen

2.2 PL/SQL Tuning

2.3 SQL*Forms Tuning

3 Fazit

Inhalt

1 Einleitung

In einem großen Datenbanksystem spielt die Performance der Datenbank eine sehr große Rolle. Angefangen von der Systemplanung, der Programmierung bis hin zum Testen des fertigen Programms darf die Performance eines Systems nicht vernachlässigt werden. Jede Veränderung des Datenbanksystems kann die Performance beeinträchtigen. Ziel des Tunings ist, daß die Organisation bzw. die Anwender finanzielle und menschliche Vorteile voll ausschöpfen können, wobei der Neuerwerb von Hardware nicht erforderlich ist. Mittels Tuning wird die Antwortzeit des Systems verkürzt, so daß lange Wartezeiten entfallen und effizienter gearbeitet werden kann.
Verantwortlich für die Performance einer Datenbank ist sowohl der Systemadministrator als auch der Systemplaner/-manager, der Designer, der Programmierer, der Datenbankadministrator und der Systemadministrator.
Die Ursachen einer schlechten Datenbankperformance können vielfältig sein. Sie werden unterteilt in die Bereiche: Design und Entwicklung, System Ressourcen, Speicherprobleme, Disk I/O-Probleme, CPU Auslastungsprobleme und Netzwerkprobleme.
In den nächsten Kapiteln wird das Tuning aus der Sicht des Programmierers, insbesondere des SQL-Tunings, weiter vertieft.

2 Tuning einer Datenbank aus der Sicht des Programmierers

Der Programmierer ist verantwortlich für die Entwicklung einer Applikation und für die Verbesserung der Antwortzeit bzw. der Kapazitätsauslastung des entsprechenden Programmes. Dieses Ziel kann bei einer Datenbank durch die Optimierung des sogenannten SQL-Statements ( Structured Query Language = Sprache zur Definition bzw. Manipulation von Datenbanken) erreicht werden.
In dieser Arbeit wird SQL von ORACLE Datenbanksystem verwendet (ORACLE 6 und 7). Bei einer ORACLE Datenbank hat der Programmierer 2 Möglichkeiten, das System zu optimieren: das SQL-Statement selbst und/oder die darauf aufbauenden Werkzeuge, d.h. PL/SQL und SQL*Forms.
Das Optimieren von SQL selbst wird im Abschnitt 2.1 besprochen. Das Optimieren der beiden Werkzeuge wird im Abschnitt 2.2 und 2.3 kurz skizziert.

2.1 SQL-Tuning

Es bieten sich mehrere Möglichkeiten, das SQL-Statement anzugeben. Die Wahl von SQL ist dann korrekt, wenn die gestellten Fragen schnellstmöglich beantwortet werden können, ohne daß die Leistung des Systems hierdurch benachteiligt wird. Das SQL-Statement ist so zu programmieren, daß es effizient und schnell in jeder Applikation laufen kann.
Vor der SQL-Optimierung müssen zunächst jedoch einige Fragen beantwortet werden, die für die Optimierung von großer Bedeutung sind.

2.1.1 Wichtige Kriterien für die Optimierung

Für die Optimierung eines Datenbanksystems müssen folgende Aspekte beachtet werden:
Je geringer der Zugriff auf die physischen Datenbankblöcke ist, desto weniger muß eingelesen werden, desto schneller arbeitet die Datenbank.
Das Datenbankdesign ist von großer Bedeutung, die nicht unterschätzt werden darf. Bestehen Wissenslücken über das Design, so kann der Versuch der Optimierung ins Gegenteil umschlagen. Zudem muß von Beginn an die zukünftige Planung des Systems berücksichtigt werden.
Zu Beginn sollte definiert werden, welche Schnelligkeit erreicht werden muß.
Das Datenvolumen darf bei der Optimierung nicht unterschätzt werden. Bei einer Testdatenbank ist das Volumen verhältnismäßig gering, so daß es der realen Applikation nicht entspricht.
Die Optimierung stellt einen fortlaufenden Prozeß dar, d.h. bei jeder Änderung (Indexänderungen, neue Felder, usw.) muß die Applikation bzw. das SQL-Statement neu optimiert werden.

2.1.2 Der Optimizer

Der Optimizer berechnet den optimalen Ausführungspfad eines SQL-Statements. Um diesen optimalen Ausführungspfad zu erreichen, sucht der Optimizer nach folgenden Informationen:
detaillierte Syntax des SQL-Statements,
Bedingungen, die erfüllt sein müssen (WHERE-Klausel),
Datenbanktabellen, auf die zugegriffen werden muß,
Indexe, welche in der Datenbank vorhanden sind,
Hints (Nur bei ORACLE 7),
Statistiken, die vom ANALYZE-Befehl erstellt worden sind (Nur bei ORACLE 7).
Bei dem Versuch, die Leistung eines Datenbanksystems zu verbessern, müssen SQL-Statements miteinander verglichen werden. Der Vergleich dient der Auslese der schnellsten bzw. effizientesten SQL-Statements. Für diesen Vergleich stellt ORACLE eine EXPLAIN PLAN-Diagnose-Befehl zur Verfügung. Durch diesen Befehl besteht die Möglichkeit, den inneren Optimierungsvorgang zu beobachten, verschiedene SQL-Statements durchzuführen, um dann die Ergebnisse miteinander vergleichen zu können.
ORACLE bietet zwei Alternativen zur Optimierung von SQL:
Optimierung mittels Regeln (rule-based Optimizer).
Hierbei werden die Indexe und die vordefinierten Regeln benutzt, um den optimalen Pfad zu berechnen. (Z.Bsp.: wenn eine Spalte in der Datenbank einen Index besitzt, so benutzt der Optimizer diesen Index, ohne noch einmal zu überprüfen, ob dieser Index wirklich eine Verbesserung der Leistung bewirkt). Diese Methode ist bei ORACLE 6 und 7 vorhanden.
Kostenbasierte Optimierung (cost-based Optimizer).
Dies ist eine verbesserte Optimierungsmethode. Hierbei werden die Informationen benutzt, die in der Datenbank vorhanden sind (Tabellengröße, Anzahl der Datensätze, Verteilung des Schlüssels). Diese Informationen sind vorhanden, nachdem der ANALYZE-Befehl für die Tabellen durchgeführt wurde. Der ANALYZE-Befehl sammelt Statistiken über die Tabellen, Datenmenge, Indexe und speichert sie in der Data-Dictionary der Datenbank ab. Diese Methode ist nur bei ORACLE 7 vorhanden.
In der Version 7 von ORACLE kann explizit gesagt werden, welche Optimierungsmethode benutzt werden soll.
Abgesehen von diesen beiden Optimierungsmethoden muß beachtet werden, daß der Optimizer nicht allwissend ist. So erkennt der Optimizer nicht, wie eine Datenbank konstruiert ist oder welche Funktion eine Datenbank besitzt.

2.1.3 Tuning per Hand

Mit der Version 7 von ORACLE kann SQL auch per Hand optimiert werden. Mittels einer Bemerkung wird die Entscheidung des Optimizers überschrieben. So wird nun, anstelle des zuvor vom Optimizer berechneten Pfades, ein alternativer Pfad durchgeführt, z.Bsp.: SELECT ... FROM /*+ RULE */ FROM EMP, DEPT WHERE ... Diese Bemerkung /*+ RULE */ bedeutet, daß der Optimizer nun die Optimierung mittels Regeln anstatt der kostenbasierten Optimierung nutzt.

2.1.4 Teilen des SQL-Statements

Nachdem der optimale Ausführungspfad für das SQL-Statement berechnet wurde, behält die ORACLE Datenbank sie im Speicher, da diese Berechnung ein lang andauernder Prozeß ist. Es gibt zwei unterschiedliche Methoden, wie diese Speicherung stattfindet:
Program-Global-Area für ORACLE 6.
Jeder Prozeß bzw. jedes Programm hat seinen eigenen Speicherbereich. Jedes SQL-Statement, welches durchgeführt wird, wird in diesem Bereich gespeichert. Wenn der gleiche Benutzer bzw. das gleiche Programm ein gleiches SQL-Statement erneut abschickt, so wird erst in dem Speicherbereich gesucht. Wenn dort das gleiche SQL-Statement gefunden wird, so braucht das System den optimalen Ausführungspfad nicht noch einmal zu berechnen.
System-Global-Area für ORACLE 7.
Bei diesem System gibt es nur einen einzigen gemeinsamen Speicherbereich. D.h., alle Benutzer bzw. alle Programme greifen auf den gleichen Bereich zu. Diese Methode ist vorteilhaft, da alle Benutzer bzw. alle Programme das SQL-Statement erst in dem gemeinsamen Speicherbereich suchen. Wird das gleiche SQL-Statement gefunden, so braucht das System den optimalen Ausführungspfad nicht noch einmal zu berechnen.
Leider existiert ein Schwachpunkt bei ORACLE. ORACLE führt einen reinen Stringsvergleich durch, d.h.: Leerzeichen, Groß- und Kleinschreibung sind von Bedeutung, z.Bsp.: SELECT * FROM EMP ist nicht identisch mit SELECT * from EMP.

2.1.5 Die Reihenfolge der Tabellennamen

Eine der wichtigsten Möglichkeiten für die Optimierung unter ORACLE 6 besteht in der Reihenfolge der Tabellennamen, so daß das SELECT-Statement so effizient wie möglich ausgewählt wird. Bei ORACLE 7 wird diese Möglichkeit nicht oft genutzt, da auf die obengenannte kostenbasierte Optimierung zurückgegriffen wird.
Wenn mehr als zwei Tabellen in der FROM-Klausel des SELECT-Statements benutzt werden, z.B.: SELECT COUNT (*) FROM EMP, DEPT, so ist die Reihenfolge der Tabellen von großer Bedeutung für die Performance.
Wenn das System die Optimierung mittels Regeln benutzt, so kann es keine intelligente Entscheidung treffen. Es benutzt einfach die Reihenfolge der Tabellennamen. In dem obengenannten Beispiel verarbeitet das System erst die DEPT Tabelle, dann die EMP Tabelle (von rechts nach links).
Die Tabelle, die als Erste eingelesen wird, nennt man Lenktabelle. Unter ORACLE 6 ist es sehr wichtig, welche Tabelle als Lenktabelle benutzt wird. ORACLE 6 benutzt intern eine sort/merge-Prozedur (Sortier- und Mischprozedur), um zwei Tabellen zu verbinden. Zuerst wird die erste Tabelle, also die Lenktabelle gelesen und sortiert, dann die zweite Tabelle. Anschließend werden die Reihen von der zweiten Tabelle mit der ersten Tabelle gemischt. Wenn die Lenktabelle (DEPT) sehr groß (z.B.: 16.000 Datensatz) und die zweite Tabelle (EMP) sehr klein ist (z.B.: 1 Datensatz), dann ist das Sortieren von der Lenktabelle sehr aufwendig. Dieser Vorgang beeinträchtigt die Geschwindigkeit. Zum Vergleich: mit der großen Lenktabelle braucht das System 26 Sekunden, um SELECT COUNT (*) FROM EMP, DEPT durchzuführen, wobei im umgekehrten Fall (SELECT COUNT (*) FROM DEPT, EMP) das System nur 0,9 Sekunden braucht. Deshalb ist die Auswahl der Lenktabelle von großer Bedeutung. Mit ORACLE 7 existiert dieses Problem nicht, da das System intelligent genug ist, um selbständig auszuwählen, welche Lenktabelle es benutzt. Sollen drei Tabellen miteinander verbunden werden, so sollte die Tabelle, welche die meisten Abhängigkeiten zu den anderen beiden Tabellen besitzt (Schnittabellen), zur Lenktabelle ausgewählt werden.

2.1.6 Die Reihenfolge der Kondition im WHERE-Statement

Die Reihenfolge der Kondition im WHERE-Statement stellt ebenfalls eine Möglichkeit der Optimierung dar. Bei ORACLE 6 ist es wichtig, wie die Reihenfolge der Kondition spezifiziert wird. Bei ORACLE 7 ist die hier beschriebene Optimierungsmethode nur relevant für das manuelle Tuning des SQL-Statements. Wie unter Punkt 2.1.2 beschrieben, basiert die Optimierung mittels Regeln auf vordefinierten Regeln. Wie diese Regeln verteilt sind, kann von der sogenannten Zustandstabelle abgelesen werden. ORACLE benutzt diese Zustandstabelle, um berechnen zu können, welcher Index für die Berechnung des optimalen Pfades benutzt werden soll.
Der erste Rang in dieser Zustandstabelle ist die ROWID = Konstante, d.h.: der Optimizer benutzt den Index von ROWID, wenn dieses Statement vorhanden ist. Wenn zwei Indexe innerhalb einer Tabelle benutzt werden, so entscheidet sich ORACLE, indem es die Ränge der Zustände miteinander vergleicht. Benutzt wird der Zustand mit dem höheren Rang. Sollten die beiden Indexe jedoch denselben Rang besitzen, so benutzt ORACLE die Reihenfolge der Kondition im WHERE-Statement.
Das ROWID-Statement stellt die schnellste Methode zum Wiederfinden von Datensätzen dar. Es sollte generell immer das ROWID-Statement benutzt werden, um ein schnelles Ergebnis zu erreichen.

2.1.7 Optimierung des Zugriffs auf die Datenbank

Jedesmal wenn ein SQL-Statement ausgeführt wird, muß ORACLE mehrere interne Operationen durchführen. D.h., daß das Statement eingelesen werden muß, die Indexe analysiert und die Datenblöcke gelesen werden müssen. Je größer die Reduktion dieses Vorganges ist, desto geringer ist der Ballast der Datenbank. Besonders wichtig ist die Optimierung des Zugriffs, wenn das System als Client/Server eingesetzt wird. Ein Client/Server-System verfolgt immer das Ziel, den Verkehr im Netzwerk zu reduzieren, so daß die Antwortzeiten der Programme gering sind. Eine Verbund-Operation (z.B.: von zwei Tabellen) ist normalerweise effektiver als zweimal ein SQL-Statement durchführen zu lassen oder aber den Gebrauch des Cursors und zweimal Einfügen (FETCH-Operation).

2.1.8 DECODE-Statement

Es wird oft eine Methode benötigt, um die Anzahl der Datensätze bzw. die Summe von bestimmten Spalten zu berechnen. Das DECODE-Statement stellt eine sehr effiziente Methode hierfür dar. Mit dem DECODE-Statement kann verhindert werden, daß mit der gleichen Tabelle eine Verbund-Operation durchgeführt werden muß oder die Selektion von gleichen Datensätzen mehrmals ausgeführt wird. Das DECODE-Statement kann auch im ORDER BY- und im GROUP BY-Statement benutzt werden. Anstatt mehrmals gleiche SQL-Statements mit verschiedenen ORDER BY- bzw. GROUP BY-Statements anzugeben, kann das DECODE-Statement benutzt werden. Es ist zu beachten, daß das DECODE-Statement keinen Index benutzen kann, d.h. es benutzt eine interne sort/merge-Prozedur. Weil dies ein langsamer Prozeß ist, sollte es nur benutzt werden, wenn die Anzahl der Datensätze gering ist, die durch das WHERE-Statement zurückgegeben wurden.

2.1.9 Weitere Tips zur Verbesserung der Performance

In diesem Teil werden noch einige Tips angegeben, welche zur Verbesserung der Performance des SQL-Statements beitragen können.
Vereinigung von einfachen, nicht zueinander in Beziehung stehender Datenbankzugriffe:
Die Performance läßt sich verbessern, indem mehrere einfache SQL-Statements vereinigt werden. Geschieht dies nicht, so wird ein SQL-Statement mehrmals ausgeführt, das System muß das Statement immer wieder einlesen, verarbeiten und entsprechende Datensätze lesen. Folglich würde dies zu einer Verschlechterung der Durchlaufgeschwindigkeit im Netzwerk führen.
Löschen von doppelten Datensätzen:
Um dies effizient zu erreichen, sollte das ROWID-Statement benutzt werden. Dieses Statement arbeitet effizient, um die gleichen EMP_NO Datensätze in der Tabelle EMP zu löschen:
DELETE FROM EMP E
WHERE E.ROWID > ( SELECT MIN(X.ROWID)
FROM EMP X
WHERE X.EMP_NO = E.EMP_NO)
Berechnung der Anzahl der Datensätze von der Tabelle (COUNT-Statement):
Die Reihenfolge der Effizienz des COUNT-Statements ist wie folgt definiert: COUNT (auf einer indizierten Spalte) ist das schnellste, COUNT (*) ist das zweitschnellste und COUNT (1) ist das langsamste Statement.
Nutzung von WHERE anstatt HAVING:
Generell sollte das HAVING-Statement vermieden werden, da das HAVING-Statement die ausgewählten Datensätze herausfiltert, nachdem es alle Datensätze gelesen, sortiert oder summiert hat.
Tuning von Views:
Die Performance des Views kann auch wie ein normales SQL-Statement optimiert werden.
Minimierung des Tabellenzugriffs in einer Abfrage:
Um die Performance zu verbessern, kann der Tabellenzugriff in einer Abfrage minimiert werden, insbesondere wenn in dem SQL-Statement sub-query-SELECT (Abfrage in einer Abfrage) oder mehrere Spalten UPDATE-Statement vorkommen.
Nutzung von Alias:
Es sollte immer Alias benutzt werden, wenn mehrere Tabellen im SQL-Statement vorhanden sind. Erstens verringert dies die Verarbeitungszeit des SQL-Statements, zweitens verhindert dies Syntaxfehler, die von mehrdeutigen Namen verursacht werden.
Nutzung von NOT EXIST anstatt NOT IN:
In sub-query-Klausel verursacht NOT IN intern eine sort/merge-Prozedur. Diese ist dann nicht effizient.
SELECT ...
FROM EMP
WHERE DEPT_NO NOT IN (SELECT DEPT_NO
FROM DEPT
WHERE DEPT_CAT = 'A')
verursacht eine sort/merge-Prozedur-Berechnung. Für die Verbesserung der Performance muß dies ersetzt werden durch:
SELECT ...
FROM EMP E
WHERE NOT EXIST (SELECT *
FROM DEPT
WHERE DEPT_NO = E.DEPT_NO
AND DEPT_CAT = 'A')
Nutzung von Verbundoperationen anstatt EXIST:
Wenn möglich, sollten generell Verbundoperationen für die Benutzung von EXIST mit sub-query-Klausel bevorzugt werden.
Nutzung von EXIST anstatt DISTINCT:
Dieses Beispiel:
SELECT DISTINCT DEPT_CODE, DEPT_NAME
FROM DEPT D, EMP E
WHERE D.DEPT_CODE = E.DEPT_CODE
ist weniger effizient als:
SELECT DEPT_CODE, DEPT_NAME
FROM DEPT D
WHERE EXIST ( SELECT *
FROM EMP E
WHERE E.DEPT_CODE = D.DEPT_CODE).
EXIST ist in diesem Fall schneller, da der Datenbank-Kernel erkennt, daß die sub-query-Klausel bereits einmal erfüllt ist. Hiernach kann die Abfrage terminiert werden.

2.1.10 Nutzung von Indexen

Allgemein gibt es zwei verschiedene Methoden, um Datensätze von der Tabelle wiederzufinden: Nutzung von Indexen und full table scan (sequentielles Lesen von der Tabelle ohne Index). Beide Methoden haben ihre Stärken und Schwächen. Es kann nicht generell gesagt werden, daß die Nutzung von Indexen immer schneller als full table scan ist.
Full table scan kann effizient sein, da es eine geringere Bewegung des Plattenkopfes erfordert. Der Kopf der Festplatte liest die Datenblöcke sequentiell vom Anfang bis zum Ende. Ein indizierter Zugriff holt die Datensätze in logischer Folge, und nicht nach der Art und Weise, wie sie physisch auf der Festplatte gespeichert sind. Unter Umständen können aus diesem Vorgang viele Bewegungen des Plattenkopfes resultieren. Die Entscheidung zwischen Nutzung von Indexen und von full table scan hängt dann von der Größe der Tabelle und von dem Muster des Zugriffs auf die Tabelle ab. Die Hersteller von ORACLE empfehlen, full table scan statt eines indizierten Zugriffs zu benutzen, wenn das SQL-Statement bzw. die Abfrage von Tabellen weniger als acht Datenblöcke beinhaltet. Für größere Tabellen ist normalerweise ein indizierter Zugriff schneller als full table scan.
Bei einem SQL-Statement, das nur die indizierten Spalten oder Pseudospalten (USER, COUNT(*), usw.) in der Tabelle benutzt, kann davon ausgegangen werden, daß die Nutzung des indizierten Zugriffs schneller ist. In diesem Fall wird nur der Index gelesen. Die physischen Datensätze werden nicht gelesen.
Gelegentlich ist es effizienter, erst den Index in der Tabelle zu löschen, wenn viele Datensätze in eine Tabelle einfügt werden sollen. Nach dem Einfügen kann der Index wiederherstellt werden. Dieser Vorgang ist effizienter, da sonst nach dem Einfügen eines Datensatzes der Index jedesmal neu aktualisiert wird.
Es gibt keine absolute Richtlinie zur Nutzung von Indexen oder full table scan. Es sollte immer eine Tabellensituation zuvor überprüft werden.
Zusätzlich muß folgendes für die Optimierung beachtet werden:
Kombination von Indexen:
Nutzung von zu vielen Indexen in einer Tabelle kann die Performance verschlechtern. ORACLE verschmelzt bzw. kombiniert den Index für eine Tabelle, solange es kann. Wenn ein SQL-Statement über zwei oder mehrere gleiche Indexe in verschiedene Tabellen in dem Ausführungspfad verfügt, so benutzt ORACLE beide Indexe. Diese Indexe werden gemischt, und nur die Datensätze, die gemeinsam zu den Indexen gehören, werden gelesen.
Wenn die beiden Indexe in der gleichen Tabelle in einem WHERE-Statement existieren, berechnet ORACLE erst den Rang. Ein Index mit UNIQUE-Statement hat einen höheren Rang als ein Index ohne UNIQUE-Statement. Wenn beide Indexe ein UNIQUE- bzw. kein UNIQUE-Statement besitzen, so ist der Rang abhängig davon, ob die Indexe sich in der gleichen oder in verschiedenen Tabellen befinden. Wenn zwei gleiche Indexe in zwei verschiedenen Tabellen existieren, so bestimmt die Tabellenreihenfolge die Bearbeitungsfolge. Wenn zwei gleiche Indexe in zwei gleichen Tabellen existieren, so erhält der erste Index im WHERE-Statement den höheren Rang (die Reihenfolge in WHERE-Statement).
Es sollte beachtet werden, daß ein UNIQUE- (oder non UNIQUE-) WHERE-Vergleich einen sehr hohen Rang bei dem Optimizer besitzt, aber nur, wenn der Vergleich zwischen Konstanten bzw. Variablen stattfindet.
Wenn die Indexe die Prädikate Gleichheit und Ungleichheit gleichzeitig in einer Tabelle benutzen, kann ORACLE diese Indexe nicht mischen. In diesem Fall benutzt es nur das Prädikat Gleichheit. Bei einem unklaren Rangsieger benutzt ORACLE den ersten Index im WHERE-Statement.
Ausschalten von bestimmten Index:
Beispiel:
SELECT ...
FROM EMP
WHERE EMP_TYPE = 'A'
AND EMP_CLASS = 'X'.
Die Spalte EMP_TYPE ist indiziert (non-UNIQUE) und EMP_CLASS ist nicht indiziert. Der Optimizer merkt, daß EMP_TYPE indiziert ist und benutzt diesen Index. Wird später ein zweiter Index (non-UNIQUE) auf EMP_CLASS eingefügt, so wird der Optimizer beide Indexe benutzen, indem er eine sort/merge-Prozedur ausführt. Dies kann unter Umständen zu einer Verschlechterung der Performance führen. In diesem Fall kann der Index von EMP_CLASS von der Betrachtung des Optimizers wie folgt (mit dem || Operator) ausgeschaltet werden:
SELECT ...
FROM EMP
WHERE EMP_TYPE = 'A'
AND EMP_CLASS || = 'X'.
Vermeidung einer Berechnung auf einer indizierten Spalte:
Generell benutzt der Optimizer keinen Index, sondern full table scan, wenn die indizierte Spalte ein Teil von einer Funktion (im WHERE-Statement) ist. MIN- und MAX-Funktionen bilden eine Ausnahme.
Automatisches Ausschalten von Indexen:
Unter bestimmten Umständen schaltet das System besondere Indexe aus. Z.B.: Eine Tabelle besitzt zwei oder mehrere Indexe. Einer der Indexe ist UNIQUE und der andere ist non-UNIQUE. In diesem Fall nutzt ORACLE nur den UNIQUE-Index und ignoriert den anderen.
Einfügen von Spalten in einem Index:
Gelegentlich ist es effizienter, eine zusätzliche Spalte in einen Index zu integrieren. Dies ist empfehlenswert, wenn die Spalte klein ist (kein 30-String Feld) und oft benutzt wird. In allen anderen Fällen lohnt es sich nicht.
Vermeidung von NOT in einer indizierten Spalte:
Allgemein sollte die Nutzung eines NOT-Vergleichs in einer indizierten Spalte verhindert werden, da ORACLE ansonsten full table scan anstatt dem Index benutzt. In bestimmten Fällen transformiert ORACLE NOT-Operator zu mit diesen korrespondierenden Funktionen (z.B.: NOT > zu <=, usw.).
Nutzung von UNION statt OR:
Generell sollte ein UNION-Statement (im WHERE-Statement) benutzt werden, wenn die Spalten indiziert sind. Die Nutzung von OR auf indizierten Spalten verursacht ein full table scan anstatt eines indizierten Wiederfindens.
Vermeidung von Null-Werten in Indexen:
Ein Null-Wert kann nicht verglichen werden. Deshalb sollte er als Teil von Indexen vermieden werden. Die Nutzung von Null-Werten an einer falschen Stelle kann zu einer Verschlechterung der Performance führen. Die Nutzung von Null-Werten kann auf einer indizierten Spalte das indizierte Suchen unterlassen, so daß statt dessen ein full table scan stattfindet, weil Null-Werte nicht zu der Domäne von Indexen gehören.
Nutzung von Null-Werten für eine Markierung:
Obwohl normalerweise die Nutzung von Null-Werten Probleme beinhaltet, können sie sehr effizient für eine Markierung (flag) benutzt werden. Anstatt irgendeine Variabel zu benutzen, welche den Speicherplatz beansprucht, können Null-Werte benutzt werden. Null-Werte werden nicht im Index gespeichert, so daß auf diesem Weg Speicherplatz gespart werden kann.

2.2 PL/SQL Tuning

PL/SQL (Procedure Language/SQL) ist eine Reihe von Prozeduren, die die Möglichkeiten des SQL-Statements erweitern. PL/SQL kann mit SQL kombiniert werden, um die Programmierung der Applikation zu vereinfachen. PL/SQL verbessert die Performance, insbesondere bei dem Datenbankzugriff auf ein Netzwerksystem, da PL/SQL mehrere SQL-Statements auf einen Block komprimiert. PL/SQL optimiert den Zugriff, indem der gesamte Block auf einmal abgeschickt wird. Die Nutzung von PL/SQL ist unter Umständen besonders effizient bei einem Batch-Update. Mittels PL/SQL kann die Performance verbessert werden, es sind jedoch bestimmte Aspekte zu beachten. Hierfür ist primär das zugrundeliegende SQL-Statement zu überprüfen, da sich hier die meisten Probleme befinden.

2.3 SQL*Forms Tuning

SQL*Forms wird benutzt, um eine interaktive, formularbasierte Applikation zu erstellen. Es besteht die Möglichkeit, das SQL-Statement und PL/SQL in SQL*Forms zu integrieren. Um SQL*Forms zu optimieren, sollte wie bei PL/SQL das zugrundeliegende SQL-Statement als erstes überprüft werden, da sich hier 90% der Probleme befinden. Es gibt mehrere Aspekte, die bei der Optimierung von SQL*Forms beachtet werden müssen. Eine Ausführung dieser Aspekte würde jedoch den Rahmen dieser Arbeit sprengen.

3 Fazit

Tuning eines Datenbanksystems, insbesondere SQL-Tuning, verlangt eine kontinuierliche Arbeit. Die Performance eines Systems muß fortwährend beobachtet und analysiert und der Situation entsprechend angepaßt werden. Die Veränderung von Tabellenvolumen, der Anzahl der zur Verfügung stehenden Indexe und der physischen Lage stellen die Ursache dar, daß das SQL-Statement jedesmal neu angepaßt werden muß. Zusätzlich bieten neue Versionen von ORACLE jedesmal neue Möglichkeiten zur Optimierung.
Die Optimierungsverfahren, von Optimierung mittels Regeln bis zu der kostenbasierten Optimierung, werden fortlaufend verbessert. Zusätzlich bietet sich dem Programmierer noch die Möglichkeit, per Hand weiter zu optimieren. Bei der Benutzung der von ORACLE angebotenen Werkzeuge sollte darauf geachtet werden, daß die Ursache einer schlechten Performance bei dem zugrundeliegende SQL-Statement liegen kann.
Die Optimierung der Performance eines Datenbanksystems ist grenzenlos. Daher muß das Ziel der Performance selbst definiert werden, da sich die Optimierung des SQL-Statements nur bis zu einem bestimmten Punkt lohnt. Hiernach steht die zu erbringende Zeitinvestition für die Optimierung in keiner Relation zu den immer weiter sinkenden Hardwarekosten.