Hysterie um Histogramme

Werbung
Hysterie um Histogramme
Autoren: Michael Lindermann und Roger Niemeyer, ORDIX AG, Paderborn
DOAGNews Q4_2005
Dieses Werk ist urheberrechtlich geschützt. Die dadurch begründeten Rechte, insbesondere
die der Übersetzung, des Nachdrucks, des Vortrags, der Entnahme von Abbildungen und
Tabellen, der Funksendung, der Mikroverfilmung oder der Vervielfältigung auf anderen
Wegen und der Speicherung in Datenverarbeitungsanlagen, bleiben, bei auch nur auszugsweiser Verwertung, vorbehalten. Eine Vervielfältigung dieses Werkes oder von Teilen dieses
Werkes ist auch im Einzelfall nur in den Grenzen der gesetzlichen Bestimmungen des
Urheberrechtes der Bundesrepublik Deutschland vom 9. September 1965 in der jeweils
geltenden Fassung zulässig. Sie ist grundsätzlich vergütungspflichtig. Zuwiderhandlungen
unterliegen den Strafbestimmungen des Urheberrechtsgesetzes.
©2005
Zur möglichst effizienten Ausführung von SQL-Statements kann bei Oracle der Cost-BasedOptimizer eingesetzt werden. Dieser erstellt den Ausführungsplan anhand statistischer Informationen, die über die Daten vorliegen. Dabei spielt die Güte der Statistik eine große Rolle, aber auch
andere Faktoren sind zu berücksichtigen. Dieser Artikel richtet sich an Datenbank-Administratoren, die sich mit dem Thema Statistikerzeugung unter Oracle 9 und 10 beschäftigen. Es
werden Details angesprochen, die für den kostenbasierenden Optimizer von Oracle wichtig sind.
Durch die Analyse von Tabellen kann man sich Performance-Vorteile verschaffen – aber auch
zunichte machen.
Gegenüber dem regelbasierten Optimizer (RBO), der ein starres Regelwerk bei der Erstellung des
Ausführungsplans abarbeitet, fließen bei dem Cost-Based-Optimizer (CBO) auch statistische Daten
bei der Entscheidungsfindung ein. Dies ist insbesondere dann von Vorteil, wenn die Daten nicht
gleich verteilt sind. Mithilfe von Statistiken kann eine Aussage zur Selektivität der Daten getroffen
werden. Damit bietet der CBO ein wichtiges Kriterium für den Ausführungsplan. Auf dieser
Grundlage trifft er eine Vorhersage für die günstigste Zugriffsart oder die optimale Join-Order.
Als Beispiel betrachten wir eine einfache Tabelle T1 bei der in der Spalte C1 die Werte 1 bis 20
auftreten. Die absolute Häufigkeit der einzelnen Werte ist in Abbildung 1 dargestellt. Der Wert 5
kommt mit deutlichem Abstand am häufigsten vor, die restlichen Zahlen sind in etwa gleich verteilt.
Abb. 1: Absolute Häufigkeit der Werte der Beispieltabelle.
Wird für T1 eine einfache Statistik erzeugt (ANALYZE TABLE oder dbms_stats.gather_table_stats
ohne FOR-Klausel) geht Oracle zunächst von einer Gleichverteilung der Datensätze aus. Das
bedeutet, dass bei einem SELECT wie in Abbildung 2 ein Index-Zugriff stattfindet, da vermeintlich
1/20, also 5 Prozent der Gesamtdaten betroffen sind. Das zeigt auch der zugehörige Ausführungsplan in Abbildung 2. Ein Full-Table-Scan (FTS) wäre an dieser Stelle effizienter gewesen
(siehe Abbildung 3). Deutlich erkennbar ist die Diskrepanz zwischen geschätzten und realen
Kosten.
©2005
SQL> select * from t1
where c1 = 5;
13280 Zeilen ausgewahlt.
Ausfuhrungsplan
---------------------------------------------------0
SELECT STATEMENT Optimizer=CHOOSE (Cost=42
Card=942 Bytes=195936)
1
0 TABLE ACCESS (BY INDEX ROWID) OF 'T1'
(Cost=42 Card=942 Bytes=195936)
2
1 INDEX (RANGE SCAN) OF 'T1_C1_IDX'
(NON-UNIQUE) (Cost=2 Card=942)
Statistiken
---------------------------------------------------0
recursive calls
0
db block gets
27071
consistent gets
0
physical reads
0
redo size
232771 bytes sent via SQL*Net to client
10390 bytes received via SQL*Net from client
887
SQL*Net roundtrips to/from client
0
sorts (memory)
0
sorts (disk)
13280
rows processed
Abb. 2: Ausführungsplan, nach Ermessen des Cost-Based-Optimizers.
©2005
SQL> select /*+ full(T1) erzwinge FTS */ * from t1
where c1 = 5
13280 Zeilen ausgewahlt.
Ausfuhrungsplan
----------------------------------------------------0
1
SELECT STATEMENT Optimizer=CHOOSE (Cost=106 Card=942 Bytes=195936)
0
TABLE ACCESS (FULL) OF 'T1' (Cost=106 Card=942 Bytes=195936)
Statistiken
----------------------------------------------------0
recursive calls
0
db block gets
1546 consistent gets
41
0
physical reads
redo size
232851 bytes sent via SQL*Net to client
10390 bytes received via SQL*Net from client
887
SQL*Net roundtrips to/from client
0
sorts (memory)
0
sorts (disk)
13280
rows processed
Abb. 3: Ausführungsplan mit Hinweis auf den Full-Table-Scan.
Histogramme zur Darstellung von “Schieflagen”
Um dem CBO Informationen über die Verteilung der Daten zur Verfügung zu stellen, müssen
erweiterte Statistiken generiert werden. Dies geschieht in Form von Histogrammen, die von
ANALYZE TABLE oder dbms_stats.gather_table_stats mit FOR-Klausel erzeugt
©2005
werden. Dabei kann die Granularität über die Anzahl der zu erzeugenden Intervalle als sizeParameter übergeben werden. Bei (großen) Tabellen mit vielen unterschiedlichen Werten wird ein
so genanntes Height-Based-Histogramm erzeugt. Die Bezeichnung kommt daher, weil die
Unterteilung der Daten so erfolgt, dass in jedem Intervall etwa gleich viele Daten liegen.
Betrachten wir dazu wieder unser Beispiel von oben. Zur Abschätzung der Zahlenverteilung sollen
zehn Intervalle benutzt werden:
((Beginn Programmcode))
SQL> exec dbms_stats.gather_table_stats('RN', 'T1', method_opt =>
'for columns c1 size 10');
((Ende Programmcode))
Um die Intervalle alle „auf eine Höhe“ zu bringen, muss – eine Ungleichverteilung vorausgesetzt –
die Intervallbreite variabel sein. Dabei kann es vorkommen, dass sich ein einzelner Wert über
mehrere Intervalle erstreckt. Anders ausgedrückt, haben dann mehrere Intervalle denselben
Endpunkt.
In der View USER_TAB_HISTOGRAMS kann man sich das Histogramm ansehen: Die Spalte
ENDPOINT_NUMBER gibt die Intervallnummer an und ENDPOINT_VALUE den Wert an der
Intervallgrenze.
((Beginn Programmcode))
SQL> select * from user_tab_histograms
where table_name = 'T1'
order by column_name, endpoint_value
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_ACTUAL_VALUE
-------------------- ----------------------- ------------------------------ -------------------------- ---------------------------------------T1 C1 0 1
T1 C1 1 5
T1 C1 2 5
T1 C1 3 5
T1 C1 4 5
T1 C1 5 5
T1 C1 6 5
T1 C1 7 5
T1 C1 8 8
T1 C1 9 15
T1 C1 10 20
((Ende Programmcode))
Abb. 4: Darstellung des Histogramms in USER_TAB_HISTOGRAMS. Die farblich markierten Zeilen 2 – 7
werden in der View nicht dargestellt und sind hier nur zum besseren Verständnis eingefügt.
Kommen Intervallgrenzen mehrfach vor, wird nur die mit der höchsten Intervallnummer
ausgegeben. Bei zehn Intervallen repräsentiert dann jedes einzelne ein zehnprozentiges Vorkommen
der Werte im Intervall.
©2005
In unserem Beispiel ist der Wert „5“ Endpunkt von sieben Intervallen, woraus auf ein Vorkommen
von etwa 70 Prozent geschlossen werden kann. Den restlichen Zahlen bleibt demnach insgesamt nur
eine Häufigkeit von 30 Prozent. Dies spiegelt die tatsächlichen Verhältnisse sehr gut wieder. Mit
Hilfe dieses Histogramms entscheidet sich der CBO nun auch ohne Hint für einen Full-Table-Scan
wenn nach der Zahl „5“ selektiert wird. In allen anderen Fällen wird weiterhin über den Index
gegangen.
Ein nicht ganz so präzises, aber in unserem Beispiel völlig ausreichendes Ergebnis hätte man auch
mit der Intervallzahl „3“ erzielen können: Die „5“ ist Endpunkt zweier Intervalle und hat damit eine
geschätzte Häufigkeit von 2/3. Hier lohnt sich ein Full-Table-Scan!
„Value Based“ – „Height Based“
Ein Sonderfall tritt auf, wenn die Intervallanzahl größer oder gleich der Anzahl der
unterschiedlichen Werte der betreffenden Spalte ist (siehe Spalte NUM_DISTINCT in
USER_TAB_COLUMNS).
Abb. 5: Value Based-Histogramm der Tabelle T1.
Dann kann jeder Wert in ein eigenes Intervall fallen und es wird ein Histogramm im klassischen
Sinne erzeugt. Im Gegensatz zum zuvor beschriebenen wird es auch als „Value Based“ bezeichnet.
In diesem Fall muss die Spalte ENDPOINT_NUMBER anders interpretiert werden, nämlich als
©2005
kumulierte Histogrammhöhe. Das heißt, in diesem Fall kann man die tatsächliche Häufigkeit eines
Wertes berechnen, indem man von seiner ENDPOINT_NUMBER die des Vorgängers abzieht.
Ab Oracle 10g ist die Art des Histogramms in der View USER_TAB_COLUMNS in der Spalte
HISTOGRAM hinterlegt. Mögliche Werte sind „none“, „frequency“ (value based) und „height
balances“ (height based). Leider ist diese Spalte in Oracle 9i noch nicht verfügbar. Trotzdem ist
eine Unterscheidung möglich. Generell kann nur bei einem Height-Based-Histogramm in der Spalte
ENDPOINT_NUMBER eine „0“ auftauchen. Bei einem Value-Based-Histogramm macht nämlich
der Wert „0“ keinen Sinn, da hier die ENDPOINT_NUMBER, wie oben beschrieben, für die Anzahl
der Häufigkeit eines Wertes steht. In jedem Intervall liegt aber genau ein Wert und damit muss die
Häufigkeit mindestens eins sein.
dbms_stats und ANALYZE arbeiten bezüglich des SIZE-Parameters unterschiedlich. Wird das
ANALYZE-Kommando mit einem SIZE-Wert aufgerufen, der gleich der Anzahl unterschiedlicher
Werte der entsprechenden Spalte ist, dann wird erwartungsgemäß ein Value-Based-Histogramm
erzeugt. Dbmbs_stats mit dem gleichen SIZE-Wert erzeugt weiterhin ein Histogramm vom Typ
Height-Based. Erst wenn eine gewisse Schwelle, die deutlich über NUM_DISTINCT liegen kann,
überschritten wird, werden auch hier Value-Based-Histogramme erzeugt. In unserem Beispiel
(NUM_DISTINCT=20) ist der Grenzwert 27!
Problemfall Bind-Variablen
Wird per SQL-Statements auf Tabellen zugegriffen, für die Histogramm-Statistiken vorhanden sind,
und die Bind-Variablen enthalten, müssen auch diese beim ersten Ausführen geparst werden. Um
den Ausführungsplan zu erzeugen, wird die Bind-Variable dabei einmalig durch ihren aktuellen
Wert ersetzt.Der Ausführungsplan ist damit zukünftig für dieses Statement festgelegt. Das
Histogramm wird später nicht mehr berücksichtigt. Diese Strategie wird als "Bind Peaking"
bezeichnet. Erwischt man nun zufällig einen Wert, der einen Full-Table-Scan nach sich zieht,
werden alle folgenden Statements ebenso per Full-Table-Scan abgearbeitet, selbst wenn aufgrund
der Statistik ein Index-Range-Scan vorteilhafter wäre.
Der Ausführungsplan ändert sich erst dann wieder, wenn die entsprechenden Informationen aus
dem Shared-Pool verdrängt werden. Das kann durch die Neuerzeugung von Statistiken, ein Leeren
des Shared-Pools oder einen Neustart der Instanz geschehen.
Der Widerspruch besteht also darin, dass bei stark ungleich verteilten Daten eine HistogrammStatistik sinnvoll ist, diese aber durch die Verwendung von Bind-Variablen zunichte gemacht wird.
Es gibt mehrere Möglichkeiten diesen Widerspruch aufzulösen:
• Über den bool'schen Parameter _optim_peek_user_binds kann man das Verhalten von
Oracle beeinflussen. Ändert man den Wert von true (standard) auf false, wird kein BindPeeking durchgeführt und der Optimizer verhält sich regelbasiert (RBO). In unserem Beispiel
bedeutet das, dass immer über den Index gegangen wird.
©2005
• Man verzichtet auf Bind-Variablen im Code, der auf solche Tabellen zugreift. Dann ist aber
auch mit einem erhöhten Parsing-Aufwand zu rechnen. Dies ist aber dann gut vertretbar, wenn
der Anteil des Parsens im Vergleich zur Laufzeit des Kommandos gering ist.
• Man verzichtet auf die Statistiken – was bei mehr oder weniger gleich verteilten Daten sowieso
zu empfehlen ist.
Fazit
Histogramme sollten mit Bedacht eingesetzt werden. Man muss sich gut überlegen, ob sich der
Einsatz wirklich lohnt und im ersten Schritt zunächst mit einfachen Statistiken arbeiten. Außerdem
kostet die Erstellung und Pflege der Statistiken natürlich auch Zeit und Ressourcen. Histogramme
bringen einen Performance-Gewinn, wenn die Daten asymmetrisch verteilt sind. Der Einsatz von
Bind-Variablen an dieser Stelle kann den gewonnenen Vorteil allerdings wieder zunichte machen.
Kontakt:
Roger Niemeyer und Michael Lindermann
[email protected]
Begriffserklärungen
Bind-Variable Häufig vorkommende Statements müssen jedes Mal geparst
werden, auch wenn sie sich nur durch Parameterwerte
unterscheiden. Bei Verwendung von Bind-Variablen muss nur
einmal geparst werden.
Bind-Peaking
Beim ersten Parsen werden Bind-Variablen durch ihren
tatsächlichen Wert ersetzt, falls Histogramme zur Verfügung
stehen.
Cost-Based-Optimizer (CBO) Der kostenbasierte Optimizer erstellt Ausführungspläne
aufgrund statistischer „Überlegungen“.
Rule-Based-Optimizer (RBO)
Ausführungspläne werden nach einem starren Regelwerk
erstellt.
Full-Table-Scan (FTS)
Zugriffsart auf Tabellen, bei der bis zur High-Water-Mark
gelesen wird.
High-Water-Mark (HWM)
Die High-Water-Mark ist der höchste Füllgrad eines
Segmentes, der dort bisher erreicht wurde.
Histogramm
Grafische Darstellung der Häufigkeitsverteilung von (Mess)Werten.
©2005
Herunterladen