ORACLE DATENBANKOPTIMIERUNG (BASICS)

May 22, 2016 | Author: Gerhard Krüger | Category: N/A
Share Embed Donate


Short Description

Download ORACLE DATENBANKOPTIMIERUNG (BASICS)...

Description

ORACLE – DATENBANKOPTIMIERUNG (BASICS) INHALT 1 Motivation ........................................................................................................................................... 1 2 Automatische, regelmäßige DB-Optimierung ..................................................................................... 2 2.1 Index-Rebuild ................................................................................................................................ 2 2.2 Tabellen-Reorganisation ............................................................................................................... 2 2.3 Statistiken ermitteln ..................................................................................................................... 3 2.4 Alles automatisiert ........................................................................................................................ 3 3 Performance-Monitoring..................................................................................................................... 4 3.1 V$SESSION_LONGOPS................................................................................................................... 4 3.2 V$SQL, V$SQL_AREA ..................................................................................................................... 5 4 Performance-Tuning durch DB-Indizes................................................................................................ 6 4.1 Fremdschlüssel-Indizes ................................................................................................................. 6 4.2 Identifizierung anhand hoher Kosten bei SQL-Statements .......................................................... 6 5 Zusammenfassung ............................................................................................................................... 9

1 MOTIVATION In einem Kundenprojekt standen wir vor dem Problem, dass die Anwendung – und scheinbar auch die Oracle-Datenbank-Instanz selber - über die Jahre immer langsamer geworden ist. Wir haben das Problem lange Zeit auf die ständig anwachsenden Datenmengen und mangelnde Optimierung in der Persistenzschicht der Applikation geschoben. Als ein externer Oracle-Berater dann einen Blick auf die Produktiv-Datenbank geworfen hat, wurden uns einige Nachlässigkeiten im Umgang mit der Datenbank aufgezeigt. Im Folgenden möchte ich die wesentlichen Punkte der Performance-Analyse und -Tunings kurz skizzieren. Dies ist sicherlich kein

Oracle-Optimierungs-Workshop für Fortgeschrittene ist, sondern vielmehr wird das Rüstzeug eines Anwendungsentwicklers beschrieben, der z.B. per JDBC-Treiber auf Oracle-Datenbanken zugreift. Desweiteren sollte man (ggf. mit Hilfe eines Oracle-Experten) ausfindig machen, ob der Datenbankserver selber richtig dimensioniert ist. Man kann mithilfe geeigneter SQL-Statements und Tools leicht herausfinden, ob es z.B. einen File-IO-Engpass auf dem DB-Server gibt oder einen Hauptspeichermangel. Wenn solche „Mängel“ vorliegen, sollten natürlich auf der Hardware-Seite entsprechende Aufrüstungsmaßnahmen ergriffen werden. Die folgenden Aufgaben liegen teilweise in der Verantwortung des Datenbankadministrators und teilweise in der des Softwareentwicklers.

2 AUTOMATISCHE, REGELMÄßIGE DB-OPTIMIERUNG Der DB-Administrator sollte dafür sorgen, dass folgende Aufgaben regelmäßig ausgeführt werden: (Regelmäßig ist ein sehr relativer Begriff – aber das hängt stark von den einzelnen Datenbanken, der Verfügbarkeit, der Anzahl Schreibzugriffe, etc. ab. Es schadet aber nicht, mindestens jede Woche, z.B. am Wochenende, oder auch jede Nacht, wenn weniger oder keine Last auf der DB herrscht, die Optimierungen automatisch durchführen zu lassen (z.B. per SQL mittels Cron-Job – wahrscheinlich geht das auch mit Oracle-Administrationstools). 2.1 INDEX-REBUILD Durch Analyse der Systemtabelle „USER_INDEXES“ und geeigneten SQL-Befehlen kann man herausfinden, welche Indices degeneriert sind und neu angelegt werden sollten – aber auch, welche Indizes überflüssig sind. Index-Rebuild mittels: ALTER INDEX REBUILD;

Es ist sinnvoll, alle Indizes in einem eigenen Tablespace zu speichern. Gleichzeitig mit einem IndexRebuild kann man ggf. das Verschieben in den Tablespace „INDX“ folgendermaßen durchführen: ALTER INDEX REBUILD TABLESPACE INDX;

2.2 TABELLEN-REORGANISATION Eine Defragmentierung von Tabellen durch deren Neuaufbau(„Rebuild“) ist von Zeit zu Zeit durchzuführen: ALTER TABLE MOVE TABLESPACE USERS;

Verschiebt die Tabelle in einen anderen Tablespace und erstellt sie neu. Wenn der Tablespace derselbe ist wie zuvor, so wird die Tabelle lediglich reorganisiert (defragmentiert).

Eine Reorganisation einer Tabelle bzw. eines DB-Index wird empfohlen, wenn sich die Datenmenge durch viele INSERT oder DELETE-Statements oder Importe signifikant verändert hat! 2.3 STATISTIKEN ERMITTELN Oracle benötigt u.a. zur Optimierung von SQL-Abfragen aktuelle Statistiken über alle Tabellen und Indizes. Diese müssen regelmäßig ermittelt werden. Je nach Konfiguration der Datenbank werden die Statistiken automatisch neu erzeugt. Bei einem Datenbankimport geschieht das typischerweise auch automatisch. Ermittlung, wann zuletzt Statistiken über DB-Entitäten erhoben worden sind: SELECT owner, table_name, last_analyzed FROM owner='APPLICATION_XYZ';

dba_tab_statistics WHERE

SELECT table_name, last_analyzed from dba_tables where Owner = 'APPLICATION_XYZ'; SELECT index_name, last_analyzed from dba_indexes where Owner = 'APPLICATION_XYZ'; EXIT;

Manuelle Ermittlung der Statistiken: // internal DataDictionary-Stats: call dbms_stats.gather_fixed_objects_stats(); // System-Stats: call dbms_stats.gather_dictionary_stats(); // Perform object statistics for tables and indices CALL dbms_stats.gather_index_stats('', ''); CALL dbms_stats.gather_Table_stats('', '');

2.4 ALLES AUTOMATISIERT Folgendes SQL-Skript erzeugt alle Statements, um sämtliche Indizes und Tabellen zu reorganisieren und alle Statistiken neu zu berechnen. Diese Statements können dann regelmäßig – zum Beispiel jedes Wochenende - ausgeführt werden. SET PAGESIZE 0; SET LINESIZE 200; call dbms_stats.gather_dictionary_stats(); SPOOL tmp_OracleRebuildIndices.sql SELECT 'ALTER INDEX '||owner||'.'||index_name||' REBUILD TABLESPACE INDX;' FROM dba_indexes WHERE Owner = 'APPLICATION_XYZ'; SPOOL OFF SPOOL tmp_OracleGatherIndexStats.sql SELECT 'CALL dbms_stats.gather_index_stats(''COMPIERE'', '''|| index_name ||''');' FROM dba_indexes WHERE Owner = 'APPLICATION_XYZ'; SPOOL OFF

SPOOL tmp_OracleAnalyzeIndices.sql SELECT 'ANALYZE INDEX '||owner||'.'||index_name||' COMPUTE STATISTICS;' FROM dba_indexes WHERE Owner = 'APPLICATION_XYZ'; SPOOL OFF SPOOL tmp_OracleGatherTableStats.sql SELECT 'CALL dbms_stats.gather_table_stats(''COMPIERE'', '''|| table_name ||''');' FROM dba_tables WHERE Owner = 'APPLICATION_XYZ'; SPOOL OFF exit;

3 PERFORMANCE-MONITORING Oracle besitzt mit den V$_-Views sogenannte Dynamic Performance Views. Sie enthalten dynamische Informationen zu laufenden und vergangenen SQL-Anfragen, DB-Sessions, und vielem mehr, die vom DB-Server automatisch ermittelt und bei Abfrage durch den SYSTEM-User aktualisiert werden. Wichtige Views sind z.B. V$SQL, V$SQLAREA, V$SESSION, V$SESSION_LONGOPS. 3.1 V$SESSION_LONGOPS Auflisten teurer, langlaufender Aktionen mit ihrem verursachten „Aufwand“ und Laufzeit in der DB: select OPName, Target, Message, TOTALWORK, ELAPSED_SECONDS, START_TIME, Last_Update_Time from V$Session_LongOps where username='COMPIERE' order by TOTALWORK desc

Ergebnis z.B.: OPNAME

TARGET

MESSAGE TOTALWORK

ELAPSED_SECONDS

------------------------------------------------------------------------------Table Scan

COMPIERE.OCP_CRM_CORRESPONDENCE

Table Scan: 88381 Table Scan

11 COMPIERE.PWORKITEMS

Table Scan: 82432 Table Scan

COMPIERE.PWORKITEMS: 82432 out of 82432 Blocks done 43

COMPIERE.PBPEPROCESSINSTS

Table Scan: 23552 Table Scan

COMPIERE.OCP_CRM_CORRESPONDENCE: 88381 out of 88381 Blocks done

COMPIERE.PBPEPROCESSINSTS: 23552 out of 23552 Blocks done 66

COMPIERE.M_TRANSACTION

Table Scan: 19277

COMPIERE.M_TRANSACTION: 19277 out of 19277 Blocks done 18

Massnahmen: Langlaufende Operationen oder teure “Full Table Scans“ könnten auf fehlende oder nicht optimale DB-Indizes hindeuten. Eventuell kann man auch DB-Zugriffe in der Anwendung optimieren (weniger Daten holen, Cachings einbauen, etc.).

3.2 V$SQL, V$SQL_AREA 3.2.1 Ermittlung der Ausführungsdauer von SQL-Abfragen (Top 10): select * from ( select sql_text,executions,cpu_time from v$sql where executions>0 order by cpu_time/executions desc )where rownum= 20 ORDER BY 1 DESC

3.2.3 Aufspüren unperformanter SQL-Befehle: Der folgende Befehl zeigt für die SQL-Befehle, die sich im SQL-Cache befinden, wie oft sie ausgeführt wurden und wie viele Blockzugriffe sie zur Abarbeitung benötigten. (BUFFER_GET = Blockzugriff = Lesen eines Speicherbereiches von der Harddisk in den Speicher  relativ teure Operation) Außerdem wird die Trefferquote des Befehls im Datencache angezeigt. Damit lassen sich sehr schnell "schlecht optimierte" SQL-Befehle herausfinden. Trefferquoten kleiner 70% deuten regelmäßig darauf hin, dass eine Tabelle vollständig ohne Index-Zugriffe gelesen wird. Da die Statistik nur die Befehle anzeigt, die sich gerade im SQL-Cache befinden, muss die folgende Abfrage ggf. mehrfach täglich zu unterschiedlichen Zeitpunkten aufgerufen werden. SELECT TO_CHAR(EXECUTIONS, '999G999G990') "EXECUTIONS", TO_CHAR(BUFFER_GETS, '999G999G990') "GETS", TO_CHAR(BUFFER_GETS/GREATEST(NVL(EXECUTIONS,1),1), '999G999G990') "GETS_PER_EXEC", TO_CHAR (ROUND(100*(1-(DISK_READS/GREATEST(NVL(BUFFER_GETS,1),1))),2), '990D00') TREFFERQUOTE, SQL_TEXT FROM V$SQL WHERE BUFFER_GETS > 1000 ORDER BY BUFFER_GETS DESC

Diese Query sollte man nach verschiedenen Spalten filtern/sortieren, um unterschiedliche Aussagen zu erhalten. Man kann sich z.B. SQL-Abfragen anzeigen lassen mit geringer Trefferquote („WHERE TrefferQuote < 80“), vielen IO-Zugriffen („WHERE GETS_PER_EXEC > 10000“) , vielen Ausführungen („WHERE EXECUTIONS > 100“), etc. Beispielhafte Ergebnisse: EXECUTIONS

GETS

GETS_PER_EXEC

TREFFERQUOTE

SQL_TEXT

--------------------------------------------------------------------------------------------

276

10,696,208

38,754

99.91

SELECT AD_User.AD_User_ID,NULL...

115

1,872,464

16,282

99.70

DELETE FROM OCE_ProdInvMovement WHERE...

115

1,859,686

16,171

99.84

DELETE FROM OCE_ProductionOrderLine WHERE

29

1,853,698

63,921

91.94

SELECT SUM(ol.LineNetAmt * (CASE WHEN...

TREFFERQUOTE

SQL_TEXT

…Where where Trefferquote < 80…: EXECUTIONS

GETS

GETS_PER_EXEC

-------------------------------------------------------------------------------------------36

653,400

18,150

78.72

SELECT OCP_DAMDocument_ID, Name FROM...

23

443,666

19,290

48.79

select MovementType, MovementQty from...

10

203,048

20,305

68.44

SELECT l.OCE_ProductionOrder_ID, ...

10

182,580

18,258

72.65

SELECT COUNT(ROWNUM) FROM OCP_DAMDocument

7

127,050

18,150

77.04

SELECT OCP_DAMDocument_ID FROM ...

4 PERFORMANCE-TUNING DURCH DB-INDIZES Bei der Implementierung von mehrschichtigen Java-Anwendungen und Verwendung von PersistenzFrameworks (wie z.B. Hibernate) vergisst man leicht, dass datenbanknahe Optimierungen, wie die Einführung geeigneter Datenbank-Indizes, ein enormes Potential an Performanceverbesserung bieten. 4.1 FREMDSCHLÜSSEL-INDIZES Generell sollten eigentlich alle Fremdschlüssel einer Tabelle einen eigenen Index besitzen. Beispiel: CREATE TABLE department ( deptno , dname

NUMBER(2) CONSTRAINT PK_DEPT PRIMARY KEY VARCHAR2(14)

); CREATE TABLE employee ( empno

NUMBER(4) CONSTRAINT PK_EMP PRIMARY KEY

, ename

VARCHAR2(10)

, deptno

NUMBER(2)

);

Anlegen eines Fremdschlüssel-Indizes: CREATE INDEX emp_deptno ON employee(deptno) TABLESPACE indx;

4.2 IDENTIFIZIERUNG ANHAND HOHER KOSTEN BEI SQL-STATEMENTS Ziel: Full Table Scans auf größere Tabellen sind möglichst zu vermeiden – beispielsweise durch Einführen eines einen DB-Index.

Vorgehen: 1) Man identifiziert anhand der obigen Monitoring-Möglichkeiten ein SQL-Statement, welches teuer in der Ausführung ist und/oder sehr häufig ausgeführt wird. 2) Für dieses SQL-Statement lässt man einen Ausführungsplan erstellen (in vielen SQLTools und im Oracle SQL Developer möglich ; auf Kommandozeile mittels "explain plan ..." oder „Autotrace On“) Bsp.: Auf Kommandozeile: SQL> set autotrace on SQL> set linesize 200 SQL> SELECT FROM JOIN WHERE ;

3) Für dieses SQL-Statement lässt man einen Ausführungsplan erstellen. Im Ausführungsplan kann man an den einzelnen Knoten die Kosten für die Teilstatements ablesen. Dort wo hohe Kosten sind, muss man optimieren. 4) Wenn dort "Table Access (Full)" steht, heißt das, dass kein (geeigneter) DB-Index zur Verfügung steht und ein „Full Table Scan“ durchgeführt wird, was bei großen Tabellen immer sehr schlecht ist, da alle Zeilen der Tabelle durchsucht werden müssen! Diese Full Table Scans sollte man weitestgehend eliminieren, indem man passende Indices einführt. 5) Nach der Index-Erstellung sollte erneut ein Ausführungsplan erstellt werden, um zu überprüfen, dass der Index genutzt wird und ob er kostenmäßig etwas bringt. 6) Beispiele: Bsp. 1) Fremdschlüssel-Index Zu optimierendes SQL-Statement: SELECT SUM(HandlingTime) FROM M_InOut WHERE OCE_RP_DAY_ID=1013025 AND IsActive='Y';

--> Der Execution Plan zeigt einen Full Table Scan bei der M_InOut-Tabelle an. Index erstellt: create index M_InOut_Day on M_InOut(OCE_RP_DAY_ID); -- Index Statistics generieren: CALL dbms_stats.gather_index_stats('COMPIERE', 'M_InOut_Day');

Anschließend lief der Befehl deutlich schneller und mit deutlich geringeren "Kosten" ab. Bsp. 2) Index für Spalten aus Where-Clause: Zu optimierendes SQL-Statement: SELECT SUM(OL.QTYORDERED) FROM C_ORDER O JOIN C_ORDERLINE OL ON O.C_ORDER_ID=OL.C_ORDER_ID LEFT OUTER JOIN M_INOUTLINE ML ON ML.C_ORDERLINE_ID=OL.C_ORDERLINE_ID LEFT OUTER JOIN M_INOUT M ON M.M_INOUT_ID=ML.M_INOUT_ID WHERE OL.M_PRODUCT_ID=415 AND o.AD_Org_ID=1000000 AND (o.DocStatus='DR' OR o.DOCSTATUS='IP') AND (m.DocStatus'CO' OR m.DocStatus IS NULL) AND o.ISSOTRX='N' AND o.PROCESSED='N' AND o.C_DocTypeTarget_ID NOT IN (SELECT C_DocType_ID FROM C_DocType WHERE Name='Supplier Claim')

AND ((ol.DatePromised IS NULL AND ol.DateDesired
View more...

Comments

Copyright � 2017 SILO Inc.