2017-11-22 1 views
1

Ich weiß, dass es einige Posts zum Thema Pivotieren gibt, die ich benutzt habe, um dorthin zu gelangen, wo ich heute bin (Danke an die BQ-Community!). Aber dieser Beitrag sucht nach einem Ratschlag zur Optimierung, wo eine große Anzahl von Pivot-Spalten benötigt wird, verteilte Tabellen-Joins benötigt werden ... sowie Deduplizierung. Nicht viel richtig zu fragen!BigQuery - Joining und Pivotieren von großen Tischen

Ziel:

Wir haben 2 große BQ Tabellen, mit einer vollen 10 Jahren Geschichte, die Verbindung muss:

sales_order_header (13 GB - 1,35 Millionen Zeilen) sales_order_line (50 g - 5 Millionen Zeilen)

Dies ist eine typische "Kopfzeile/Zeile" eins zu viele Beziehung. Die Daten für die Tabellen kommen als 2 separate Streams leider eher als 1 Dokumentart, wo die Zeile innerhalb der Kopfzeile verschachtelt ist, was ideal wäre - aber ihre nicht so verteilten Joins werden für einige der Ansichten notwendig, die unser BI-Tool (Tableau) benötigt in regelmäßigen Abständen (alle 60 Minuten) nennen gereinigt 'Daten aufnehmen, die:

  1. deduped (beide Tabellen, die sind)
  2. verbunden Header (auf SalesOrderID) auszukleiden
  3. jeder seine eigene Array' sourceData 'namve/value paris, das entpackt werden muss /' pivot ', so dass es kein Array ist

Punkt 3 stellt ein eigenes Problem dar. Wir haben eine Spalte mit dem Namen 'sourceData', die im Grunde die Kerndaten ist - ein Array von Stringnamen-Wertpaaren (eine Zeile in BQ ist eine Replikation einer einzelnen Zeile von einem DB, also der Schlüssel ist ein Spaltenname und Wert der Wert für eine einzelne Zeile).

Jetzt denke ich hier das Problem zu lösen, da es 250 Array-Einträge gibt (wir kennen die genaue Anzahl vorne), dies entspricht 250 'unnest' Anweisungen und den besten Ansatz benutzend, den ich Subselects verwenden kann:

(SELECT val FROM UNNEST (Source) WHERE name = 'a') AS a, 250 mal

und das als Muster für jeden der Header und die Linie Tabellen Ansichten repsective getan.

So ist die SQL für die Ansicht zum Abrufen nur eines deduktiven, flatternd/geschwenkt Array für die Tabelle Sales_order_header wie folgt. Die sales_order_line hat das gleiche Muster für seine Ansicht:

#standardSQL 
WITH latest_snapshot_dups AS (
    SELECT 
    salesOrderId, 
    PARSE_TIMESTAMP("%Y-%m-%dT%H:%M:%E*S%Ez", lastUpdated) AS lastUpdatedTimestampUTC, 
    sourceData, 
    _PARTITIONTIME AS bqPartitionTime 
    FROM 
    `project.ds.sales_order_header_refdata` 
), 
latest_snapshot_nodups AS (
    SELECT 
    *, 
    ROW_NUMBER() OVER (PARTITION BY salesOrderId ORDER BY lastUpdatedTimestampUTC DESC) AS rowNum 
    FROM latest_snapshot_dups 
) 
SELECT 
    salesOrderId, 
    lastUpdatedTimestampUTC, 
    (SELECT val FROM UNNEST(sourceData) WHERE name = 'a') AS a, 
    (SELECT val FROM UNNEST(sourceData) WHERE name = 'b') AS b, 
    ....250 of these 
FROM 
    latest_snapshot_nodups 
WHERE 
    rowNum = 1 

Obwohl nur ein hier zeigen, haben wir diese zwei ähnliche Ansichten (mit insgesamt 250 + 300 = 550 einzigartige Unterabfragen, die UNNEST/Pivot), und jetzt will ich Um den Header mit den Zeilenansichten zu verbinden, stoße ich sofort auf ein Problem, das eine Grenze von Unterabfragen überschreitet.

Gibt es einen besseren Weg, dies zu tun, vorausgesetzt, dass dies die Daten sind, mit denen zu arbeiten ist? Ein besserer Weg, um vielleicht "zu drehen"? Oder eine effizientere Möglichkeit, eine einzelne Ansicht zu erstellen, die die Reihenfolge der Dinge optimiert, anstatt zwei separate Ansichten zu verwenden?

enter image description here

Vielen Dank für Ihre Hilfe BQ Gemeinschaft!

Antwort

1

Ich laufe in ein Problem sofort eine Grenze von Subqueries

derzeit unter Muster verwenden Sie überschreiten (entfernt mot signifikanten Teil des Codes der Einfachheit halber)

#standardSQL 
SELECT 
    salesOrderId, 
    (SELECT val FROM UNNEST(sourceData) WHERE name = 'a') AS a, 
    (SELECT val FROM UNNEST(sourceData) WHERE name = 'b') AS b, 
    ....250 OF these 
FROM latest_snapshot_nodups 

unten Versuchen Muster

#standardSQL 
SELECT 
    salesOrderId, 
    MAX(IF(name = 'a', val, NULL)) AS a, 
    MAX(IF(name = 'b', val, NULL)) AS b, 
    ....250 OF these 
FROM latest_snapshot_nodups, UNNEST(sourceData) kv 
GROUP BY salesOrderId 
+0

super danke Mikhail, werde das sehr gerne ausprobieren! Eine Sache - ich kann die Verwendung einer groupBy sehen, ich habe tatsächlich etwa 10 andere Spalten, die ich in der Projektion sowie nicht nur salesOrderId in der groupBy-Anweisung (z. B. eine Reihe von Daten und eine externe ID) verwendet würde. Schränkt dies die groupBy als Option ein? –

+0

sollten Sie nur alle Gruppierungsspalten in die GROUP BY-Anweisung aufnehmen. Beispiel: GROUP BY salesOrderId, lastUpdatedTimestampUTC –