Laden von Data Marts auch mal komplex DOAG BI, 9. 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 09.06.2016
Ausgangslage Täglicher Initial Load aller Data Mart Tabellen Komplexe Berechnungen zwischen Core und Data Marts Lang laufende ETL Jobs Inkonsitente Daten in Data Marts während des Ladens 3 09.06.2016
Inkonsistente Daten während Laden des Data Marts Core Tue Mon No data Tue TRUNCATE / INSERT Mon 4 09.06.2016
Anforderungen an neue Lösung Fachliche Anforderungen Keine Ausfallzeiten der Data Marts BI Daten müssen früher verfügbar sein Technische Anforderungen Ersatz des bestehenden ETL Tools Incremental Loads von großen Faktentabellen Einheitliche Lösung für alle Data Mart Tabellen 5 09.06.2016
«Load Switch» Konzept Core Tue Mon Tue Mon Tue Mon Tue Mon Mon Tue Mon Tue Tue Mon Tue Mon TRUNCATE / INSERT Tue Mon Tue Mon 6 09.06.2016
«Load Switch» Technische Möglichkeiten Zwei Kopien aller Data Mart Tabellen Synonyme auf aktive Versionen Zwei Kopien aller Data Mart Tabellen Views auf aktive Versionen Ladetabelle für jede Data Mart Tabelle Partition Exchange 7 09.06.2016
«Data Mart Loader» Konzept Core History View Layer Load View Load Table Direct-Load INSERT 8 09.06.2016
«Data Mart Loader» Load View Load View V_LOAD_DIM_PRODUCT DWH_ID FULL_DESCRIPTION PRODUCT_CODE PRODUCT_NAME PRODUCT_SIZE PRODUCT_PRICE SUBCATEGORY_CODE SUBCATEGORY_NAME CATEGORY_CODE CATEGORY_NAME Load Table LOAD_DIM_PRODUCT DWH_ID FULL_DESCRIPTION PRODUCT_CODE PRODUCT_NAME PRODUCT_SIZE PRODUCT_PRICE SUBCATEGORY_CODE SUBCATEGORY_NAME CATEGORY_CODE CATEGORY_NAME DWH_LOAD_ID 9 09.06.2016
CREATE OR REPLACE VIEW v_load_dim_product AS SELECT p.dwh_id, CASE WHEN p.fk_subcategory_id = -1 THEN 'GLOBAL_CATEGORY/GLOBAL_SUBCATEGORY/' p.product_name WHEN s.fk_category_id = -1 THEN 'GLOBAL_CATEGORY/' s.subcategory_name '/' p.product_name ELSE c.category_name '/' s.subcategory_name '/' p.product_name END AS full_description, p.product_code, p.product_name, p.product_size, p.product_price, s.subcategory_code, s.subcategory_name, c.category_code, c.category_name FROM v_cor_product_curr p JOIN v_cor_subcategory_curr s ON (s.dwh_id = p.fk_subcategory_id) JOIN v_cor_category_curr c ON (c.dwh_id = s.fk_category_id) 10 09.06.2016
Laden von Dimensionstabellen 2. 3. 4. 1. Initial Statistics Partition Create Load Exchange & from Indexes Table View Core History View Layer Load View Load Table Dim. Table Partition 0 Direct-Load INSERT Partition Exchange Local Indexes Indexes 11 09.06.2016
Laden von Dimensionstabellen CREATE TABLE LOAD_DIM_PRODUCT PARTITION BY RANGE(DWH_ID) (PARTITION P_DUMMY VALUES LESS THAN (MAXVALUE)) AS SELECT * FROM DIM_PRODUCT WHERE 1 = 2 INSERT /*+ append */ INTO LOAD_DIM_PRODUCT SELECT... FROM V_LOAD_DIM_PRODUCT ALTER TABLE LOAD_DIM_PRODUCT EXCHANGE PARTITION P_DUMMY WITH TABLE DIM_PRODUCT INCLUDING INDEXES WITHOUT VALIDATION 12 09.06.2016
Laden von partitionierten Faktentabellen Daily Load into Monthy Partition Fact Table Fact Table Partition 0 Partition 0 Partition 1 Partition 1 Partition 2 Partition 2 Partition 3 Partition 3 Partition 4 Partition 4 Partition 5 Partition 5 Partition 6 Load Current Partition Partition 6 Partition 6 Load Historical Partitions Fact Table Partition 0 Partition 1 Partition 2 Partition 2 Partition 3 Partition 4 Partition 5 Partition 5 Partition 6 Partition 6 13 09.06.2016
Incremental Load: Herausforderungen Vollständiges Laden von Partitionen Tägliches Laden in Monatspartitionen? Korrekturen von Datensätzen in historischen Partitionen Interval Partitioning (monatlich oder täglich) Erstellung von neuen Partitionen Ermittlung der Partitionsnamen Lösung muss stabil und entwicklungsresistent sein Selbstlernend : Welche Daten wurden bereits geladen? Gleicher Aufruf für Initial und Incremental Loads Was passiert nach Strukturänderungen? 14 09.06.2016
Partition Exchange und Interval Partitioning Fact Table SYS_P38 SYS_P39 SYS_P31 SYS_P40 SYS_P32 SYS_P45 SYS_P46 'SYS_P46' Einfügen eines Datensatzes in Zieltabelle Neue Partition wird erstellt (falls notwendig) ROLLBACK Return ROWID Ermittlung des Namens der Zielpartition dbms_rowid.rowid_object Partition Exchange mit Zielpartition Verwendung von Dynamic SQL https://danischnider.wordpress.com/2012/05/01/partition-exchange-and-interval-partitioning/ 15 09.06.2016
Partition Exchange und Interval Partitioning Datensatz einfügen, um neue Partition zu erstellen und ROWID zu ermitteln INSERT INTO fact_sales VALUES v_row RETURNING ROWID INTO v_rowid; ROLLBACK; Name der Zielpartition ermitteln SELECT subobject_name INTO v_partname FROM user_objects WHERE object_id = dbms_rowid.rowid_object(v_rowid); 16 09.06.2016
Partitionen der Quelltabelle im Core ermitteln Core History View Layer HIST PART CURR HIST Relevante Partitionen aus Core Tabelle Alle Partitionen mit aktueller DWH_LOAD_ID dbms_rowid.rowid_object Erstellen von Partition View in History View Layer Dynamisch erstellt vor dem Laden des Data Marts CREATE OR REPLACE VIEW v_cor_sales_part AS SELECT * FROM cor_sales PARTITION (SYS_P12) UNION ALL SELECT * FROM cor_sales PARTITION (SYS_P17) UNION ALL SELECT * FROM cor_sales PARTITION (SYS_P18) 17 09.06.2016
Laden von Faktentabellen 1. 2. 3. 4. 5. Create Partition Incremental Statistics Temp Load Exchange & Indexes Load Table Loop History View Layer Load View Direct-Load INSERT Load Table Fact Table Partition 0 Partition 0 Temp Table Partition 1 Partition 2 Partition 2 Partition 3 Partition 4 Partition 5 Partition Partition Partition 5 Exchange Exchange Partition 6 Partition 6 Indexes Local Indexes Local Indexes 18 09.06.2016
Runtime-Metadaten für Lade-Jobs Status, um alle geladenen Tabellen in einem Schritt zu aktivieren («Load Switch») Letzte DWH_LOAD_ID zur Ermittlung der Quellpartitionen bei Incremental Load Table Name Status Start Time End Time Last Load ID DIM_PRODUCT Loaded 28.02.2016 11:18:23 28.02.2016 11:18:58 4711 DIM_CUSTOMER Loaded 28.02.2016 11:19:31 28.02.2016 11:20:13 4711 DIM_CHANNEL Loaded 28.02.2016 11:20:20 28.02.2016 11:20:47 4711 FCT_SALES Loading 28.02.2016 11:21:18 4710 FCT_ORDERS Switched 26.02.2016 05:22:12 28.02.2016 05:34:32 4708 FCT_INVOICES Switched 27.02.2016 03:56:14 28.02.2016 04:12:27 4710 19 09.06.2016
Voraussetzungen an Design Klare Architektur mit separaten DWH-Schichten Keine Loop-backs oder Shortcuts Keine Sequencen im Data Mart Klare Namenskonventionen Regeln für physisches Datenbankdesign Alle Foreign Key mit RELY DISABLE * Gleiche Partitionen in Core und Data Mart Keine globalen Indizes auf partitionerte Tabellen DWH_LOAD_ID in allen Tabellen * https://danischnider.wordpress.com/2015/12/01/foreign-key-constraints-in-an-oracle-data-warehouse/ 20 09.06.2016
Zusammenfassung Laden von Data Marts nicht immer trivial Spezialbehandlung für Incremental Loads Setzt klare Architekturrichtlinien voraus Kundenspezifische Lösung Grundideen sind wiederverwendbar Auch mit ETL Tool oder DWH-Generator einsetzbar 21 09.06.2016
Vielen Dank. Dani Schnider Principal Consultant Tel. +41 58 459 50 81 dani.schnider@trivadis.com 22 09.06.2016