Betrifft Performance-Optimierung bei Datentransformationen Autor: Christian Hellwig ([email protected]) Art der Info Technische Background Info Quelle Aus unserer Projekt- und Schulungserfahrung Einleitung Gute Performance bei Datentransformationen, oft als Teil der ETL-Prozesse in grossen OLAP-Umgebungen, ist immer wieder eine Anforderung. Wenn im OLAP-Bereich die Daten der Quellsysteme in die Oracle-Datenbank geladen werden, so ist meistens eine Transformation der Daten erforderlich, um schliesslich die Basis für ein Data Warehouse zu bekommen. Zusatzinformationen, wie die ID einer Dimension, müssen beispielsweise ermittelt oder berechnet werden. Die im Folgenden beschriebene Methode zeigt auf, wie Datentransformationen möglichst effizient durchgeführt werden können. Das gleiche Prinzip kann auch im OLTP-Bereich anstelle von grossen INSERT-, UPDATE- oder DELETE-Transaktionen zur Verbesserung der Performance verwendet werden. Unter Oracle stehen zur Verbesserung der Performance folgende leistungsfähige Methoden und Eigenschaften zur Verfügung: • • • • • • PARALLEL (Bedingung: Oracle Enterprise Edition) Direct-Load INSERT (Bedingung: Oracle Enterprise Edition) NOLOGGING CTAS (das „CREATE TABLE ... AS SELECT ...“ Statement) EXCHANGE PARTITION Transformationsfluss in mehreren Schritten Die erwähnten Methoden und Eigenschaften werden im Folgenden einzeln beschrieben. Werden nur einzelne oder, im Idealfall, alle dieser Methoden und Eigenschaften in einer Transformation mit umfangreichen Datenbeständen eingesetzt, so führt dies zu einem markanten Performancevorteil. Parallele Ausführung Während der parallelen Ausführung eines SQL-Statements arbeiten mehrere Prozesse simultan zusammen. Durch diese Verteilung auf mehrere Prozesse wird das SQL-Statement schneller ausgeführt. Die Performance wird vor allem bei Operationen mit grossen Datenmengen deutlich verbessert. Am häufigsten wird das parallele Ausführen von Prozessen im OLAP-Bereich angewendet. Aber auch im OLTP-Bereich, beispielsweise bei Batch-Verarbeitungen ausserhalb der Geschäftszeiten, kann Parallelisierung empfehlenswert sein. Parallelisierung wird typischerweise auf Multi-Prozessor-Systemen (SMP oder MPP) eingesetzt, da dort der Performancegewinn am grössten ist. Aber selbst auf Systemen mit einer CPU kann Parallelisierung zu Performanceverbesserungen führen, beispielsweise wenn asynchrones I/O verwendet werden kann. Wenn jedoch mehrere Benutzer gleichzeitig parallelisierte SELECT, INSERT, UPDATE oder DELETE Statements ausführen, können die Ressourcen (CPUs, Memory, Disks) schnell mal erschöpft sein. Bei der parallelen Ausführung eines Statements verteilt ein Dispatcher-Prozess, der sogenannte “Parallel Execution Coordinator”, die Arbeit an verschiedene Prozesse, die “Parallel Execution Servers”, welche dann das Statement parallel ausführen. Der “Parallel Execution Coordinator” gliedert die Tabelle in sogenannte “Granules” (eine gewisse Anzahl physischer Blocks). In der Regel wird jeder dieser “Granules” durch einen einzelnen “Parallel Execution Server” gelesen (es gibt Ausnahmen, auf die hier nicht im Einzelnen eingegangen wird). Wenn der “Execution Server” ein “Granule” verarbeitet hat, bekommt er vom “Execution Coordinator” das nächste “Granule”, solange noch “Granules” zum Verarbeiten vorhanden sind. Am Ende werden diese Teilresultate durch den “Execution Coordinator” zum Gesamtresultat zusammengesetzt. Die einer Operation zugeordnete Anzahl der “Execution Servers” nennt man DOP (Degree of parallelism). Das stimmt zumindest für „intra-operation parallelism“. Besteht ein Statement aus mehreren Operationen (z.B. Lesen der Daten aus der Tabelle und Sortieren der Daten), so spricht man von „inter-operation parallelism“. In diesem Fall kann die Anzahl der „Execution Servers“ doppelt so gross wie der DOP sein. Erforderlich für eine parallele Ausführung ist das Tabellenattribut PARALLEL oder der Hint PARALLEL. Zusätzlich erforderlich für paralleles DML ist das Statement “ALTER SESSION ENABLE PARALLEL DML“. Stattdessen kann auch das Statement „ALTER SESSION FORCE PARALLEL“ angegeben werden. In diesem Fall wird für alle nachfolgenden Statements der DOP der betroffenen Tabellen verwendet. Hints müssen in diesem Fall keine angegeben werden. Parallel Query: SELECT /*+ parallel (customer,8) */ ... FROM customer; Parallel DDL: CREATE TABLE customer_temp (...) PARALLEL (DEGREE 6) ... AS SELECT ... FROM customer c; Parallel DML: ALTER SESSION ENABLE PARALLEL DML; INSERT /*+ parallel (customer,12) */ ... ; DELETE /*+ parallel (customer,12) */ ... ; Parallelisierte UPDATE- und DELETE-Statements funktionierten bisher nur mit partitionierten Tabellen. Ab Oracle9i Release 2 ist dies dank dem neuen Feature „Intra-Partition Parallelism“ auch auf nicht-partitionierten Tabellen oder auf einzelnen Partitionen möglich. Momentan besteht aber noch die Einschränkung, dass dieses Feature nur verwendet wird, falls keine Bitmap Indexes auf der Tabelle bestehen. Die PARALLEL-Clause bestimmt den Default-DOP einer Tabelle für anschliessend ausgeführte SELECT und DML Statements. Der PARALLEL-Hint setzt sich über eine PARALLEL-Clause hinweg. Ein PARALLEL-Hint auf eine View wird auf alle in der View referenzierten Tabellen angewendet. Parallelisierung bei Oracle ist komplex. Detaillierte Informationen dazu können in der Oracle-Literatur nachgeschlagen werden. Direct-Load INSERT Während Direct-Load INSERT Operationen schreibt Oracle die Daten hinter der High Water Mark direkt in die Datenfiles. Freier Platz innerhalb der existierenden Daten wird nicht berücksichtigt. Constraints, welche für die referenzielle Integrität sorgen, werden ignoriert. Direct-Load INSERT Operationen, auch im Parallel Modus, müssen als eigene Transaktion ausgeführt werden. Direct-Load INSERT Operationen benötigen mehr Platz als Conventional-Path INSERT Operationen, da der Platz von gelöschten Daten (die sich natürlich vor der High Water Mark befinden) nicht wiederverwendet wird. Da in den meisten Data Warehouses jedoch in der Regel keine Daten gelöscht werden, ist dies in der Praxis kein Problem. Während Direct-Load INSERT Operationen ist ein exclusive Lock auf der Tabelle notwendig, sodass keine anderen Bearbeitungen dieser Tabelle möglich sind. Oracle führt Indexes am Ende von Direct-Load INSERT Operationen nach. Direct-Load INSERT Parallel Direct-Load INSERT wird automatisch verwendet, wenn INSERT-Statements im Parallel Modus ausgeführt werden. Der Grad der Parallelisierung kann sowohl auf der Tabelle selbst CREATE TABLE customer_temp PARALLEL (DEGREE 10) AS SELECT ...; ALTER TABLE customer_temp PARALLEL (DEGREE 6); ALTER TABLE customer PARALLEL (DEGREE 6); ALTER SESSION ENABLE PARALLEL DML; INSERT INTO customer SELECT * FROM customer_temp; COMMIT; als auch in Form eines Hints im INSERT- sowie auch im SELECT-Statement angegeben werden. ALTER SESSION ENABLE PARALLEL DML; INSERT /*+ PARALLEL (customer,6) */ INTO customer SELECT /*+ PARALLEL (customer_temp,6) * FROM customer_temp; COMMIT; Direct-Load INSERT Seriell Bei serieller Ausführung muss Direct-Load INSERT in jedem INSERT-Statement aktiviert werden durch den APPEND Hint. INSERT /*+ APPEND */ INTO customer SELECT * FROM customer_temp; COMMIT; NOLOGGING NOLOGGING reduziert die Anzahl der Redo Log Einträge. Anstatt jeden Datensatz zu loggen, wird nur der bisherige Stand der High Water Mark ins Redo Log geschrieben. NOLOGGING funktioniert sowohl mit parallelen als auch seriellen Direct-Load INSERT und CTAS-Statements. Die Ausführungszeit dieser Befehle wird dadurch verkürzt. Die Performance wird vor allem bei grossen und bei parallelisierten Tabellen durch NOLOGGING verbessert. ALTER TABLE ... NOLOGGING; ALTER TABLE ... MODIFY PARTITION ... NOLOGGING; CREATE TABLE customer_temp ( customer_no ,customer_name ,... ) NOLOGGING TABLESPACE data STORAGE ... Mit Conventional DML (INSERT, UPDATE, DELETE) hat NOLOGGING keinen Einfluss. Es werden immer alle DML-Operationen ins Redo Log geschrieben. Tabellen Modus INSERT Modus Datenbank Modus Redo Log LOGGING Direct-Path (APPEND) ARCHIVELOG Ja NOLOGGING Direct-Path (APPEND) ARCHIVELOG Nein LOGGING Conventional (NOAPPEND) ARCHIVELOG Ja NOLOGGING Conventional (NOAPPEND) ARCHIVELOG Ja LOGGING Direct-Path (APPEND) NOARCHIVELOG Nein NOLOGGING Direct-Path (APPEND) NOARCHIVELOG Nein LOGGING Conventional (NOAPPEND) NOARCHIVELOG Ja NOLOGGING Conventional (NOAPPEND) NOARCHIVELOG Ja Zusätzlich funktioniert NOLOGGING mit: • • • • • • • SQL*Loader CREATE INDEX ALTER TABLE ... MOVE PARTITION ALTER TABLE ... SPLIT PARTITION ALTER INDEX ... SPLIT PARTITION ALTER INDEX ... REBUILD PARTITION ALTER INDEX ... REBUILD CREATE TABLE AS SELECT CTAS (CREATE TABLE ... AS SELECT ...) ist eine leistungsfähige Möglichkeit, mit SQL die Transformation von grossen Datenmengen zu implementieren. Wenn eine grosse Datentransformation mit Standard SQL implementiert werden kann, entsteht durch den Einsatz der CTAS Methode ein Performancevorteil. CTAS wird typischerweise mit PARALLEL im NOLOGGING Modus ausgeführt. Die Attributdefinitionen dürfen keine Datentypen enthalten. Oracle erhält die Datentypen und Längen vom SELECT Statement. Mit CTAS wird das Resultat einer effizienten Abfrage in einer neuen Tabelle gespeichert. CREATE TABLE customer_temp ( customer_no ,customer_name ,... ) PARALLEL (DEGREE 6) NOLOGGING TABLESPACE data STORAGE (INITIAL 10M NEXT 10M PCTINCREASE 0) AS SELECT c.customer_no ,c.customer_name ,... FROM customer c; EXCHANGE PARTITION Um mit EXCHANGE PARTITION zu arbeiten, muss eine neue Tabelle erstellt werden, welche dieselbe Struktur hat wie die partitionierte Zieltabelle. Die Storage Parameter sollten ebenfalls identisch sein. Idealerweise wird die Tabelle gleich mit einem CTAS-Befehl erstellt und mit Daten gefüllt. ALTER SESSION ENABLE PARALLEL DML; CREATE TABLE customer_temp PARALLEL (DEGREE 6) NOLOGGING TABLESPACE data STORAGE (INITIAL 10M NEXT 10M PCTINCREASE 0) AS SELECT ...; Indexes und Fremdschlüssel, falls vorhanden auf der partitionierten Zieltabelle, müssen auf der neuen Tabelle auch erstellt werden, damit die Struktur der Tabelle gleich ist wie jene der partitionierten Tabelle. Nun wird die neue Tabelle mit der entsprechenden Partition ausgetauscht. Da dadurch nur die Einträge im Data Dictionary ausgetauscht werden, geht dies auch bei grossen Datenmengen sehr schnell. ALTER TABLE customer EXCHANGE PARTITION P200307 WITH TABLE customer_temp INCLUDING INDEXES WITHOUT VALIDATION; Globale Indexes sind normalerweise nach EXCHANGE PARTITION unusable, das heisst sie müssen rebuildet werden. Ab Oracle9i besteht jedoch die Möglichkeit, dass Global Indexes automatisch nachgeführt werden. ALTER TABLE customer EXCHANGE PARTITION P200307 WITH TABLE customer_temp INCLUDING INDEXES WITHOUT VALIDATION UPDATE GLOBAL INDEXES; EXCHANGE PARTITION wird idealerweise eingesetzt, wenn die Partitionierung der Zieltabelle gleich ist wie der Ladezyklus, d.h. wenn beispielsweise monatlich Daten in einen Tabelle mit Monatspartitionen geladen werden. Ein anderes typisches Einsatzgebiet von EXCHANGE PARTITION ist die Reorganisation von partitionierten Tabellen. Transformationsfluss Häufig sind für eine Datentransformation Daten aus verschiedenen Tabellen relevant, die in mehr oder weniger komplexen Transformationsschritten zusammengeführt und bereinigt werden müssen. Prozedurale Sprachen wie PL/SQL sind gut geeignet für komplexe Datentransformationen, weil damit Spezialfälle und Fehlerbehandlungen sehr einfach implementiert werden können. Sie haben aber den Nachteil, dass sie jeden Datensatz einzeln verarbeiten und dadurch weniger effizient sind als mengenorientierte Sprachen wie SQL. Mit PL/SQL lassen sich mehrere Cursors öffnen, um datensatzweise von verschiedenen Quelltabellen zu lesen. Gemäss komplexer Geschäftsregeln können nun diese Datensätze transformiert und schliesslich in die Zieltabelle geschrieben werden. Diese Verarbeitung wird als „row-based“ bezeichnet. Die Performance der „row-based“ Verarbeitung kann in PL/SQL verbessert werden, indem mit BULK Operations gearbeitet wird. Anstatt jeden Datensatz einzeln in die Zieltabelle einzufügen, werden ganze PL/SQL Tables bzw. Associative Arrays übergeben. Eine andere Möglichkeit sind Table Functions, an die als Parameter ganze Tabellen bzw. Cursors übergeben werden können. In SQL mit der CTAS-Methode wird mit ganzen Tabellen gearbeitet. Die Operationen können zudem PARALLEL und im NOLOGGING Modus ausgeführt werden, was sie deutlich schneller macht als eine PL/SQL-Prozedur. Hier spricht man von „set-based“ Verarbeitung. Das Ziel ist demnach, auch relativ komplexe Datentransformationen in SQL zu schreiben, um den Performancevorteil, welcher sich mit SQL ergibt, zu nutzen. Mit einer Gliederung in mehrere CTAS-Schritte lassen sich auch einigermassen komplexe Datentransformationen erreichen. Für jede Tabelle mit relevanten Daten ist ein CTAS-Schritt zu implementieren. Innerhalb dieser CTAS-Schritte dienen SQL-Funktionen zum Transformieren der Daten. Anstelle einer Tabelle kann in der FROM-Clause auch eine Inline View helfen, die Daten in die gewünschte Form zu transformieren. Sobald ein CTAS-Schritt erfolgreich erledigt ist, kann die temporäre Tabelle, welche durch den vorangehenden Schritt erstellt wurde, gelöscht werden. In der folgenden Darstellung wird die gewünschte Transformation der Daten nach drei CTAS-Schritten erreicht. Im anschliessenden vierten Schritt wird durch EXCHANGE PARTITION die temporäre Tabelle mit der betreffenden Partition der Zieltabelle ausgetauscht. Beispiel WHENEVER SQLERROR CONTINUE DROP TABLE customer_temp; WHENEVER SQLERROR EXIT FAILURE CREATE TABLE customer_temp ( customer_no ,customer_name ,customer_cost_center ,... ) PARALLEL (DEGREE 6) NOLOGGING TABLESPACE data STORAGE (INITIAL 10M NEXT 10M PCTINCREASE 0) AS SELECT /*+ use_hash (cust,cost) */ cust.customer_no ,cust.customer_name ,cost,cc_id ,... FROM customer_staging cust ,cost_center cost WHERE cust.periode = cost.periode AND cust.periode = TO_DATE ('&&V_PERIODE.','YYYYMM') AND cust.cc_short = cost.cc_short; WHENEVER SQLERROR CONTINUE BEGIN my_utility_package.add_partition('customer', TO_DATE('&&V_PERIODE','YYYYMM')); END; / WHENEVER SQLERROR EXIT FAILURE ALTER TABLE customer EXCHANGE PARTITION P&&V_PERIODE. WITH TABLE customer_temp INCLUDING INDEXES WITHOUT VALIDATION; WHENEVER SQLERROR CONTINUE BEGIN my_utility_package.gather_statistics('customer','' || 'P' || &&V_PERIODE || ''); END; / DROP TABLE customer_temp; Für das Erstellen von Tabellen- und Index-Statistiken sowie für das Hinzufügen von Partitionen sind eigene Prozeduren empfehlenswert. Dadurch werden einerseits die Aufrufe des Statistik-Packages dbms_stats mit den gewünschten Parametern vereinfacht, andererseits kann die Verwaltung der Partitionen, die über dynamisches SQL implementiert werden muss, in einem zentralen Package gekapselt werden. Literatur • • • • Oracle9i Database Concepts Oracle9i Data Warehousing Guide Oracle9i Database Performance Tuning Guide and Reference Oracle9i SQL Reference Zusammenfassung Performanceaspekte sind in Data Warehouses und OLAP-Datenbanken nicht nur für die Abfragen relevant, sondern auch beim Laden und Transformieren der Daten. Die beschriebenen Möglichkeiten erlauben es, mit Oracle auch grosse bis sehr grosse Datenmengen effizient zu verarbeiten. Diese und weitere Oracle-Features, die vor allem für Data Warehousing relevant sind, werden im Trivadis-Kurs „Data Warehousing mit Oracle“ detailliert erklärt. Wenn Sie also wissen möchten, wie Sie Ihr Data Warehouse effizienter machen oder was bei der Realisierung einer neuen OLAP-Datenbank beachtet werden sollte, sind Sie bei uns an der richtigen Adresse. Trivadis AG Christian Hellwig Europa-Strasse 5 CH-8152 Glattbrugg Internet: http://www.trivadis.com Mail: [email protected] Tel: Fax: +41-1-808 70 20 +41-1-808 70 21