Datenbank Tuning Patrick Schwanke
Häufige Fragen Was macht die Anwendung da eigentlich? Ist der Optimizer auf dem neuesten Stand? Wie kann ich dieses SQL tunen? Auf das SQL haben wir leider keinen Einfluss! Ist die Instanz gut dimensioniert?
Gute Antworten End-to-end-Tracing / Anwendungs-Tracing Erstellung und Pflege von Optimizer-Statistiken SQL Tuning-Techniken Stored Outlines Advisories als Hilfe zur Instanz-Parametrierung
Optimizer-Statistiken Meistens: Tradeoff zwischen Genauigkeit und Pflegeaufwand Sinnvolle Statistiken mit möglichst wenig Aufwand Empfehlung: DBMS_STATS statt ANALYZE Block Sampling Parallelisierung Berücksichtigung der Datendynamik (GATHER AUTO) Automatische Historisierung Gezieltes Manipulieren und Schreibschützen möglich Wann erstellen? Nach Batch-Jobs, vor OLTP-Betrieb Zeiten mit wenig Auslastung Histogramme vs. Cursor-Sharing?
Optimizer-Statistiken I/O-Aufwand reduzieren: Block Sampling: Alle Zeilen aus x% der Blöcke werden gelesen Parallelisierung GATHER AUTO : Statistik-Neuberechnung nur, wenn seit der letzten Berechnung mind. 10% der Zeilen geändert wurden oder ein TRUNCATE erfolgte oder die Tabelle neu erstellt wurde
Statistik-Job Für ein komplettes Schema: exec SYS.DBMS_STATS.GATHER_SCHEMA_STATS ( OwnName => 'DEMO',Granularity => 'ALL',Options => 'GATHER AUTO',Gather_Temp => FALSE,Estimate_Percent => 10,Block_sample => TRUE,Method_Opt => 'FOR ALL COLUMNS SIZE 254 ' -- Histogramme,Degree => 4 -- Parallelisierung,Cascade => TRUE,No_Invalidate => FALSE); Für Oracle9i einmalig GATHER AUTO vorbereiten: exec SYS.DBMS_STATS.ALTER_SCHEMA_TABLE_MONITORING ( OwnName => 'DEMO',Monitoring => TRUE);
Histogramme vs. Cursor-Sharing SQL mit Bindevariablen, z.b. SELECT * FROM kunden WHERE kdnr = :b1 Histogramme werden genutzt (!) Peeking Selektivität beim ersten Parsing wird genommen sinnvoll? It depends SQL mit Literalen, z.b. SELECT * FROM kunden WHERE kdnr = 15383 Histogramme werden genutzt Selektivität wird bei jedem SQL neu bewertet sinnvoll! Aber: Shared Pool
End2End-Tracing Welche SQLs setzt die Anwendung ab? Problem: Richtige Oracle-Session finden Was, wenn die Session erst gestartet wird? E2E-Tracing hilft eventuell Voraussetzung: Spezieller Service-Name, Module, Action oder Client-Info gesetzt Mit Wait-Events (default)
End2End-Tracing Anschalten: DBMS_MONITOR.SERV_MOD_ACT_TRACE_ENABLE( service_name => 'PS10',module_name => 'appmodule'); Ein Trace-File pro Oracle-Session Konsolidierung mit trcsess-tool Weiterverarbeitung wie gewohnt mit TKProf Kontrolle über View: DBA_ENABLED_TRACES
SQL-Tuning Ausführungsplan-Tabelle @?/rdbms/admin/utlxplan.sql Ausführungsplan erstellen EXPLAIN PLAN SET STATEMENT_ID = 'DOAG_SIGDB' INTO plan_table FOR SELECT Ausführungsplan anschauen Tools SELECT * FROM TABLE( dbms_xplan.display('plan_table','doag_sigdb'));
SQL-Tuning SQL Rewriting WHERE TO_CHAR(a.aufdatum,'DD.MM.YYYY') = '03.02.2005' Besser: WHERE aufdatum BETWEEN TO_DATE( ) AND TO_DATE( ) + 1 WHERE datum IS NULL Evtl. besser: WHERE datum = <maxdate> IN- versus EXISTS-Unteranfragen Anwendung muss angepasst werden
B*Tree-Index Beschleunigung von SELECTs auf Kosten von DML Index wird, beginnend am Ursprung, blockweise gescannt Dann erfolgt der Zugriff auf die Tabellenblöcke Characteristika Speicherintensiv Speichert keine NULL-Werte Gute Performance bei selektiven Auswahlbedingungen (5-10%) Clustering-Faktor beachten! Spezialfall: Funktionsbasierter Index Zum Beispiel auf UPPER(nachname ', ' vorname) Anwendung braucht nicht angepasst zu werden
Bitmap-Index Jeder Schlüsselwert wird als Bitmap gespeichert Finden der richtigen Bitmap durch internen B*Tree Beim Lesen wird Bitmap in ROWIDs übersetzt Characteristika Weniger speicheraufwändig Speichert NULL-Werte Starker Einfluss auf DML-Operationen Geeignet für OLAP, weniger für OLTP Effizient bei Kombinierten, nicht sehr selektiven Auswahlbedingungen Schnelle AND- und OR-Kombinationen über mehrere Indizes Anwendung braucht nicht angepasst zu werden
SQL-Tuning Virtuelle (simulierte) Indizes CREATE INDEX NOSEGMENT Kein echter Indexaufbau keine Tabellensperre Abschätzung von Ausführungsplan / Plankosten Index-Statistiken werden aus Tabellenstatistiken abgeleitet Voraussetzung: Histogramme Möglichst Tool-gestützt
SQL-Tuning Optimizer-Hints Join-Methoden Join-Reihenfolgen Für Select / Update / Delete oder Subqueries Syntax Kommentar gefolgt von einem Pluszeichen (+) SELECT /*+ */ nachname FROM kunden; Können kombiniert werden Tabellen-Alias muss im Hint verwendet werden Ein fehlerhafter Hint wird ignoriert Anwendung muss angepasst werden Aber es gibt einen Ausweg
Die wichtigsten Hints /*+ FULL(table) */ Zugriff über Full Table Scan /*+ INDEX(table [index, ]) */ Zugriff über Index /*+ ORDERED */ Join der Tabellen in der Reihenfolge der FROM-Klausel /*+ USE_NL(table1 [,table2, ]) */ Nested-Loop-Join (verschachtelte Schleifen) Angegeben werden die Tabellen, die an eine bereits existierende Ergebnissmenge angehängt werden sollen /*+ USE_MERGE(table1 [table2, ]) */ Tabellen werden nach Join-Kriterium sortiert und dann verglichen /*+ USE_HASH(table1 [table2, ]) */ Ähnlich wie USE_MERGE, aber mit Hash-Buckets /*+ PARALLEL(table,d,i) */ Gibt die Anzahl der Abfrage-Server an
Spezial-Hints /*+ CARDINALITY([tablespec] n) */ Tabelle bzw. Gesamtabfrage liefert n Zeilen zurück Vor allem für temporäre Tabellen oder Tabellenfunktionen /*+ SELECTIVITY([tablespec] s) */ Gesamtselektivität aller WHERE-Klauseln der Tabelle Bei WHERE-Klauseln auf voneinander abhängigen Spalten Zum Beispiel: WHERE ort = Köln AND plz LIKE 50%
Stored Outlines Speichern / Konservieren von Ausführungsplänen Transport von Ausführungsplänen zwischen Datenbanken Export / Import von Schema OUTLN Erkennung eines SQLs in Oracle anhand Hash-Wert bzw. SQL-Text Effekt wie bei Optimizer-Hints, aber: Ohne Anpassung der Anwendung!
Stored Outlines Erzeugen von Stored Outlines: Tool-gestützt manuell ALTER SESSION SET CREATE_STORED_OUTLINES = <kategorie>; SQLs ausführen Benutzen von Stored Outlines Session- oder datenbank-weit ALTER SYSTEM SET USE_STORED_OUTLINES = <kategorie>;
Automatic Tuning Optimizer
Ist die Instanz gut dimensioniert? Buffer-Cache zu klein? Buffer-Cache zu groß? Speicher besser in PGA investieren Proaktiv: Lohnt sich Investition in mehr Memory? Wieviel Shared Pool macht Sinn? Sortieren im Speicher oder auf Platte? PGA zu klein Performance leidet Oder unnötig groß Besser in Buffer-Cache investieren Java-Pool, Streams-Pool? Automatische oder manuelle Dimensionierung?
Advisories Advisory-Views geben projizierte Performance Was wäre wenn mein größer oder kleiner wäre? Buffer Cache Shared Pool PGA Java-Pool Streams-Pool Advisory-View V$DB_CACHE_ADVICE V$SHARED_POOL_ADVICE V$PGA_TARGET_ADVICE_HISTOGRAM V$JAVA_POOL_ADVICE V$STREAMS_POOL_ADVICE
Advisories Beispiele Default-Cache (8K) Eingesparte Physical Reads Eingesparte I/O-Zeit für Physical Reads SELECT size_for_estimate,size_factor,buffers_for_estimate,estd_physical_read_factor,estd_physical_reads,estd_physical_read_time FROM v$db_cache_advice WHERE name = 'DEFAULT' AND block_size = 8192 ORDER BY factor; Shared Pool Eingesparte Zeit für SQL-Parsing Objekt-Reloads SELECT shared_pool_size_for_estimate,shared_pool_size_factor,estd_lc_load_time,estd_lc_time_saved FROM v$shared_pool_advice ORDER BY factor;
Ist die Instanz gut dimensioniert? Anpassen der Instanz: Online: ALTER SYSTEM SET = <new value>; Zum nächsten Instanz-Start: ALTER SYSTEM SET = <new value> SCOPE=SPFILE; steht für: db_cache_size, shared_pool_size, pga_aggregate_target etc. Voraussetzung: Gesamtgröße <= sga_max_size Kann nicht (!) online verändert werden Von vornherein so groß wie möglich setzen Gesamt-Memory (OS + Anwendungen + PGA)