Aktivitätseinbruch

Lösung: Die parallele Aktivität bricht ein

Wie Sie sich erinnern werden, hatten wir einen Hash Outer Join mit dominanten Nullwerten. In Folge bekam der parallelen Prozess, der die Nullwerten behandelte, bei weitem die meiste Arbeit zu tun.
Wie sollen wir dies lösen? lassen Sie uns einige grundsätzliche Überlegungen anstellen.
Ein Null Wert ist ein Sonderfall . Wir vergleichen einen Null Wert im Foreign Key mit einem Primärschlüssel , der not null definiert ist. Wir können sicherlich keinen Join Treffer für die Null Werte zu finden. Daher kann jeder der parallelen Sklaven den Vergleich durchführen, solange gewährleistet ist, dass dadurch nie ein Treffer erzeugt wird.
Es lohnt sich also die Null Werte in beliebige andere Werte um zu wandeln, solange nur zwei Voraussetzungen erfüllt sind:

  1. wir müssen die Nullwerte in einer solchen Art und Weise umwandeln, dass die gleichmäßig über alle parallel Slaves verteilt werden
  2. wir müssen sicherstellen, dass im Vergleich zu vorher kein zusätzlicher Satz ins Resultat kommt

Die Lösung zu finden hat mich viel Zeit gekostet. Zuerst habe ich versucht mit negativen Werten zum Ziel zu kommen. Aber auch sie wurden auch an nur einen Parallel Prozess gesandt, genau wie die Null Werte.
Das Problem ist, dass unsere neu generierten Schlüssel etwa im gleichen Bereich wie der Primary Key der Build-Tabelle sein müssen, um über alle Slaves verteilt zu werden.
Ich hätte versuchen können über eine with Klausel den Bereich heraus zu finden, aber das hielt ich für uncool und konnte mich nicht dazu überwinden.
Stattdessen habe ich etwas anderes versucht, was ehrlich gesagt ein bisschen wie ein Hack wirkt, aber viel besser aussieht. Ich benutzte den Primary Key der äußeren Tabelle einen nicht null wertigen breit streuenden Schlüssel zu generieren.
Ich habe auch die Tatsache zunutze, dass die IDs integer waren und veränderte die Join-Bedingung zu:

FROM T_TAB1 T1
LEFT OUTER JOIN T_TAB2 T2
ON ( NVL(T2.X_ID, T2_id +0.5)    = T1.X_ID)

Das ist sicherlich ein bischen getrickst. Das einzig Positive daran ist, dass es funktioniert.
Die Aktivity Tab im Sql Monitor sah nachher so aus:

Vergleichen Sie dies mit dem vorherigen Bild. Es ist ziemlich beeindruckend.
Nun, in der Version 12 die Datenbank sollte in der Lage sein, mit schräg verteilten join Schlüsseln um zu gehen.
Aber es funktioniert nicht in jedem Fall, wie Randolf Geist feststellte.
Wenn jemand meine Lösung nicht gut findet, sollte er vielleicht er einen Blick auf_fix_control 6808773 werfen, aber ich gebe für keinen Fall Garantien ab. 😉

 

Die parallele Aktivität bricht ein

In einem meiner DWH POCs für Oracle’s Real World Performance Group bemerkten wir einen plötzlichen Einbruch in der Datenbank Aktivität. Unser Kunde verlangte eine Erklärung dafür.
Im SQL Monitor Activity Reiter sah das so aus:

Nach einer sorgfältigen Untersuchung erkannte ich, dass ein outer join die Ursache war. Formal sah dieser join so aus:

FROM T_TAB1 T1
LEFT OUTER JOIN T_TAB2 T2
ON T2.X_ID    = T1.X_ID

Das Problem war, dass 90% aller Werte in T1.X_ID Null Werte waren. Für die Aufteilung der Arbeit auf die Parallel Prozesse wurde der Hash Schlüssel benutzt. Als Folge bekam ein Parallelpozess 90% der ganzen Arbeit zugeteilt. Eine andere Aufteilung der Arbeit, etwa über einen broadcast war nicht möglich, da T1 zu gross war.
(Randolg Geist schildert das Problem ausführlich: Parallel Execution Skew – Demonstrating Skew).

Können Sie die join Bedingung so umschreiben, dass die Arbeit gleichmässig auf alle paralleln Prozesse verteilt wird? (Die Version war 11G. In version 12 sollte sich der optimizer automatisch um die Fragestellung kümmern.) Noch eine Annahme: die tabelle T2 hat einen Primary Key in Form der Spalte T2_id.