Nützliche Oracle 12c Features für Data Warehousing DOAG BI, 8. Juni 2016 Dani Schnider, Trivadis AG BASEL BERN BRUGG DÜSSELDORF FRANKFURT A.M. FREIBURG I.BR. GENEVA HAMBURG COPENHAGEN LAUSANNE MUNICH STUTTGART VIENNA ZURICH
Dani Schnider Principal Consultant und DWH/BI Lead Architect bei Trivadis in Zürich Kursleiter verschiedener Trivadis-Kurse Co-Autor des Buches «Data Warehousing mit Oracle Business Intelligence in der Praxis» 2 08.06.2016
Oracle 12c bringt viele Neuerungen auch für DWH Data Redaction APPROX_COUNT_DISTINCT Adaptive Query Optimization SQL Pattern Matching In-Memory Option Asynchronous Global Index Maintanance SQL Query Row Limits PL/SQL in SQL WITH Clause Online Statistics Gathering Vector Transformation UTL_CALL_STACK Multitenant Databases JSON Support Information Lifecycle Management Out-of-Place Materialized Views Default Values Enhancements Temporal Validity Invisible Columns IDENTITY Columns Partial Indexing 3 08.06.2016
Online Statistics Gathering 4 08.06.2016
ETL-Prozesse und Statistiken T1 T2 2000 ETL-Mapping T3 1500 DBMS_STATS.gather_table_stats (ownname => 'STG',tabname => 'T1'); DBMS_STATS.gather_table_stats (ownname => 'STG',tabname => 'T2'); 3000 1 INSERT STATEMENT 1500 2 INSERT T3 1500 3 HASH JOIN 1500 4 TABLE ACCESS FULL T1 2000 5 TABLE ACCESS FULL T2 3000 Siehe Vortrag So beschleunigen Sie Ihre ETL-Prozesse (DOAG BI 2015) 5 08.06.2016
Online Statistics Gathering Nach dem Laden einer Tabelle sollten immer Statistiken berechnet werden Ab Oracle 12c funktioniert dies automatisch in folgenden Fällen: CREATE TABLE AS SELECT CREATE TABLE T3 AS SELECT... FROM T1 JOIN T2 ON... Direct-Load INSERT in leere Tabelle (nach TRUNCATE) INSERT /*+ append */ INTO T3 SELECT... FROM T1 JOIN T2 ON... 6 08.06.2016
Online Statistics Gathering Anwendungsfälle: Zwischentabellen in ETL-Ablauf (Staging Area, Cleansing Area) Hilfstabellen für Zwischenresultate von Ladeprozessen Einschränkungen: Keine Index-Statistiken Keine Histogramme Keine Statistiken auf Partitionen und Subpartitionen Siehe: https://danischnider.wordpress.com/2015/12/23/online-statistics-gathering-in-oracle-12c/ 7 08.06.2016
Default Values 8 08.06.2016
Fehlende Attribute durch Singletons ersetzen STG_PRODUCTS Edradour 10 years Glenfarclas 105 Black Bowmore 1964 NULL Laphroaig 15 years CLS_PRODUCTS Edradour 10 years Glenfarclas 105 Black Bowmore 1964 Unknown Laphroaig 15 years INSERT INTO cls_products (product_code, product_desc) SELECT product_code, NVL(product_desc, 'Unknown') FROM stg_products; Siehe Vortrag Fehlertolerante Ladeprozesse in Oracle (DOAG BI 2012) 9 08.06.2016
DEFAULT Erweiterungen DEFAULT ON NULL wird verwendet, wenn NULL eingefügt wird DEFAULT kann eine Sequence sein (endlich!) CREATE TABLE dwh_whisky (dwh_id NUMBER(8) DEFAULT seq_whisky.nextval,whisky_code VARCHAR2(8) NOT NULL,whisky_name VARCHAR2(40) NOT NULL,price NUMBER (6,2) DEFAULT ON NULL 0,age VARCHAR2(3) DEFAULT ON NULL '< 7',distillery VARCHAR2(30) DEFAULT ON NULL 'Unknown Distillery',region VARCHAR2(30) DEFAULT ON NULL 'Unknown Region') 10 08.06.2016
IDENTITY Columns Automatische Vergabe von Sequenznummern ( auto increment column ) Im Hintergrund wird eine Sequence erstellt (ISEQ$$_nnnnn) CREATE TABLE dwh_whisky (dwh_id NUMBER(8) GENERATED BY DEFAULT AS IDENTITY,whisky_code VARCHAR2(8) NOT NULL,whisky_name VARCHAR2(40) NOT NULL,...) GENERATED BY DEFAULT AS IDENTITY GENERATED BY DEFAULT ON NULL AS IDENTITY GENERATED ALWAYS AS IDENTITY 11 08.06.2016
APPROX_COUNT_DISTINCT 12 08.06.2016
Funktion APPROX_COUNT_DISTINCT Anzahl unterschiedliche Kunden in SALES Tabelle: SELECT COUNT(DISTINCT cust_id) FROM sales Ungefähre Anzahl unterschiedliche Kunden in SALES Tabelle: SELECT APPROX_COUNT_DISTINCT(cust_id) FROM sales Neue Funktion APPROX_COUNT_DISTINCT Gleicher Algorithmus wie bei AUTO_SAMPLE_SIZE in DBMS_STATS (Oracle 11g) Für grosse Datenmengen schneller als COUNT(DISTINCT) Resultat nur ungefähr (+/- 4%) 13 08.06.2016
APPROX_COUNT_DISTINCT: Performance Quelle: https://antognini.ch/2014/10/the-approx_count_distinct-function-a-test-case/ 14 08.06.2016
APPROX_COUNT_DISTINCT: Genauigkeit Quelle: https://antognini.ch/2014/10/the-approx_count_distinct-function-a-test-case/ 15 08.06.2016
Partial Indexing 16 08.06.2016
Partial Indexing Anwendungsfälle Auf aktuellen Daten werden häufiger selektive Abfragen gemacht Index auf neuster Partition soll erst nach Abschluss des Ladens erstellt werden Partitionierung nach Statuswerten mit unterschiedlichen Abfragen 17 08.06.2016
Erstellen von Tabelle mit Partial Indexing Default auf Tabellenebene: INDEXING ON / OFF Kann pro Partition überschrieben werden CREATE TABLE t_part (n NUMBER, name VARCHAR2(40)) INDEXING OFF PARTITION BY RANGE (n) (PARTITION p1 VALUES LESS THAN (100),PARTITION p2 VALUES LESS THAN (200) INDEXING OFF,PARTITION p3 VALUES LESS THAN (300),PARTITION p4 VALUES LESS THAN (400),PARTITION p5 VALUES LESS THAN (500) INDEXING ON,PARTITION p6 VALUES LESS THAN (600) INDEXING ON ) 18 08.06.2016
Erstellen von Partial Indexes Partial Local Index CREATE INDEX idx_part_local ON t_part (name) LOCAL INDEXING PARTIAL Partial Global Index CREATE INDEX idx_part_local ON t_part (name) [GLOBAL] INDEXING PARTIAL 19 08.06.2016
Partial Local Index Index Partition P1 Index Partition P2 Index Partition P3 Index Partition P4 Index Partition P5 Index Partition P6 Table Partition P1 Table Partitition P2 Table Partitition P3 Table Partitition P4 Table Partitition P5 Table Partitition P6 INDEXING OFF INDEXING ON 20 08.06.2016
Partial Global Index Global Index Table Partition P1 Table Partitition P2 Table Partitition P3 Table Partitition P4 Table Partitition P5 Table Partitition P6 INDEXING OFF INDEXING ON 21 08.06.2016
Asynchronous Global Index Maintenance 22 08.06.2016
Globale Indizes im Data Warehouse DROP / TRUNCATE PARTITION setzt globale Indizes auf UNUSABLE Index Rebuild notwendig Problematisch bei rollenden Zeitfenstern (alte Partitionen werden gelöscht)! Globale Indizes im DWH möglichst vermeiden 23 08.06.2016
Asynchrones Nachführen von globalen Indizes In Oracle 12c können globale Indizes asynchron aktualisiert werden: Schritt 1: Partition löschen (DROP oder TRUNCATE PARTITION) ALTER TABLE sales DROP PARTITION p_2016_02 UPDATE INDEXES Index bleibt gültig, enthält aber Orphaned Entries SELECT index_name, status, orphaned_entries WHERE index_name = 'SALES_PK' INDEX_NAME STATUS ORPHANED_ENTRIES -------------- -------- ---------------- SALES_PK VALID YES 24 08.06.2016
Asynchrones Nachführen von globalen Indizes Schritt 2: Orphaned Entries aus Index löschen. Varianten: Scheduler Job SYS.PMO_DEFERRED_GIDX_MAINT_JOB dbms_part.cleanup_gidx ALTER INDEX REBUILD [PARTITION] ALTER INDEX [PARTITION] COALESCE CLEANUP dbms_part.cleanup_gidx(schema_name_in => USER, table_name_in => 'SALES ) 25 08.06.2016
Müssen die Orphans überhaupt gelöscht werden? Ja Orphans bleiben im Index und werden nicht überschrieben Index wächst, da Speicherplatz nicht freigegeben wird Ausnahme: Unique Indexes, falls gleicher Eintrag wieder eingefügt wird Siehe Richard Foote s Oracle Blog https://richardfoote.wordpress.com/2013/08/02/12c-asynchronous-global-index-maintenance-part-i-where-are-we-now/ https://richardfoote.wordpress.com/2013/08/06/12c-asynchronous-global-index-maintenance-part-ii-the-space-between/ https://richardfoote.wordpress.com/category/asynchronous-global-index-maintenance/ 26 08.06.2016
Vector Transformation 27 08.06.2016
Vector Transformation Phase 1 (für jede Dimension mit Filterkriterien) 1. Scan auf Dimensionstabelle (inkl. Filterung der Daten) 2. Ermittlung von Key Vector 3. Aggregation der Daten (In-Memory Accumulator) 4. Erstellen von temporärer Tabelle Phase 2 5. Full Table Scan auf Faktentabelle, Filterung anhand von Key Vectors 6. Aggregation mittels HASH GROUP BY / VECTOR GROUP BY 7. Join auf temporäre Tabellen (Join Back) 8. Ev. Join von weiteren Dimensionen (ohne Filterkriterien) 28 08.06.2016
Vector Transformation DIM1 11 Alpha 12 Alpha 13 Beta 14 Beta 15 Beta 16 Gamma 17 Delta 18 Delta DIM2 21 X green 22 X blue 23 Y green 24 Y blue 25 Y red 26 Z red FACTS 11 22 1000 11 24 1200 12 21 300 12 22 3200 12 24 700 13 22 1100 14 21 2000 14 24 800 14 25 1600 14 26 700 15 23 1100 15 24 1200 15 26 500 16 22 2400 16 23 800 17 22 1300 17 25 1100 18 21 900 18 24 2100 18 26 600 SELECT D1, D21, D22, SUM(FACTS.F) FROM FACTS JOIN DIM1 ON (...) JOIN DIM2 ON (...) WHERE D1 IN ('Beta', 'Gamma') AND D21 = 'Y' GROUP BY D1, D21, D22 29 08.06.2016
Vector Transformation DIM1 11 Alpha 12 Alpha 13 Beta 14 Beta 15 Beta 16 Gamma 17 Delta 18 Delta DIM2 21 X green 22 X blue 23 Y green 24 Y blue 25 Y red 26 Z red KV1 0 0 1 1 1 2 0 0 KV2 0 0 1 2 3 0 TMP1 1 Beta 2 Gamma TMP2 1 Y green 2 Y blue 3 Y red FACTS 11 22 1000 11 24 1200 12 21 300 12 22 3200 12 24 700 13 22 1100 14 21 2000 14 24 800 14 25 1600 14 26 700 15 23 1100 15 24 1200 15 26 500 16 22 2400 16 23 800 17 22 1300 17 25 1100 18 21 900 18 24 2100 18 26 600 0 0 0 2 0 0 0 0 0 2 1 0 1 0 1 2 1 3 1 0 1 1 1 2 1 0 2 0 2 1 0 0 0 3 0 0 0 2 0 0 Beta Y green 1100 Beta Y blue 2000 Beta Y red 1600 Gamma Y green 800 30 08.06.2016
------------------------------------------------------------------- 0 SELECT STATEMENT 1 TEMP TABLE TRANSFORMATION 2 LOAD AS SELECT SYS_TEMP_0FD9D662E_84B3F4 3 VECTOR GROUP BY 4 KEY VECTOR CREATE BUFFERED :KV0000 * 5 TABLE ACCESS FULL PRODUCTS 6 LOAD AS SELECT SYS_TEMP_0FD9D662F_84B3F4 7 VECTOR GROUP BY 8 KEY VECTOR CREATE BUFFERED :KV0001 * 9 TABLE ACCESS FULL CUSTOMERS 10 HASH GROUP BY * 11 HASH JOIN 12 MERGE JOIN CARTESIAN 13 TABLE ACCESS FULL SYS_TEMP_0FD9D662E_84B3F4 14 BUFFER SORT 15 TABLE ACCESS FULL SYS_TEMP_0FD9D662F_84B3F4 16 VIEW VW_VT_83032D7B 17 VECTOR GROUP BY 18 HASH GROUP BY 19 KEY VECTOR USE :KV0000 20 KEY VECTOR USE :KV0001 21 PARTITION RANGE ALL * 22 TABLE ACCESS FULL SALES ------------------------------------------------------------------- 31 08.06.2016 1 2 3
------------------------------------------------------------------------- 0 SELECT STATEMENT 1 TEMP TABLE TRANSFORMATION 2 LOAD AS SELECT SYS_TEMP_0FD9D6696_84B3F4 3 VECTOR GROUP BY 4 KEY VECTOR CREATE BUFFERED :KV0000 * 5 TABLE ACCESS INMEMORY FULL PRODUCTS 6 LOAD AS SELECT SYS_TEMP_0FD9D6697_84B3F4 7 VECTOR GROUP BY 8 KEY VECTOR CREATE BUFFERED :KV0001 * 9 TABLE ACCESS INMEMORY FULL CUSTOMERS 10 HASH GROUP BY * 11 HASH JOIN 12 MERGE JOIN CARTESIAN 13 TABLE ACCESS FULL SYS_TEMP_0FD9D6696_84B3F4 14 BUFFER SORT 15 TABLE ACCESS FULL SYS_TEMP_0FD9D6697_84B3F4 16 VIEW VW_VT_83032D7B 17 VECTOR GROUP BY 18 HASH GROUP BY 19 KEY VECTOR USE :KV0000 20 KEY VECTOR USE :KV0001 21 PARTITION RANGE ALL * 22 TABLE ACCESS INMEMORY FULL SALES ------------------------------------------------------------------------- 32 08.06.2016 1 2 3
Vielen Dank. Dani Schnider Principal Consultant Tel. +41 58 459 50 81 dani.schnider@trivadis.com 33 08.06.2016