Mittwoch, November 21, 2012

Parallelisierung (Randolf Geist) - Teil 1

In der Reihe der OTN-Artikel zum Thema Database Performance & Availability wurde zuletzt eine zweiteilige Serie Understanding Parallel Execution von Randolf Geist veröffentlicht, die einen sehr guten Überblick zu den Voraussetzungen und Leistungen paralleler Operationen liefert (wobei die Aussagen für Exadata, aber auch für "normale" Datenbanken gelten).

Mein Exzerpt erhebt dabei mal wieder keinen Anspruch auf Vollständigkeit, sondern soll mir in erster Linie als Erinnerungshilfe dienen. Grundsätzlich würde ich ohnehin jedem, der sich mit Parallelisierung beschäftigt, die komplette Lektüre der beiden OTN-Artikel empfehlen. Außerdem ist das Thema mal wieder eines, bei dem ich am Übersetzen der technischen Begriffe scheitere, so dass kein wirklich konsistenter Text daraus wird:

Im ersten Artikel erklärt der Autor die Voraussetzungen für einen sinnvollen Einsatz paralleler Operationen:
  • wenn der serielle Plan nichts taugt (falsche Join Reihenfolge, ungeeignete Zugriffsverfahren), wird auch der parallele Plan keine Wunder bewirken
  • wenn PL/SQL-Funktionen eingesetzt werden, die nicht explizit als parallelisierbar definiert wurden, kann es vorkommen, dass im Plan ein Schritt PX COORDINATOR FORCED SERIAL erscheint, der bedeutet, dass der Plan letztlich seriell ausgeführt wird, obwohl PX-Operationen darin erscheinen (es gibt offenbar neben den Funktionen noch andere Gründe für dieses Verhalten). Da aber das Costing die Parallelisierung berücksichtigt, kann dieser Effekt zu massiven Fehlkalkulationen führen.
  • durch das verwendete Consumer/Producer-Modell kommt es vor, dass beide Gruppen paralleler Slave-Prozesse beschäftigt sind, wenn im Plan eigentlich eine parallele Weiterverarbeitung vorgesehen ist. In solchen Fällen treten blocking operations auf, die im Plan als BUFFERED oder BUFFER SORT ausgewiesen sind (wobei BUFFER SORT in seriellen Plänen eine andere Semantik hat). Dieses Abwarten ist inhaltlich nicht immer nachvollziehbar (der Autor zeigt das Problem am Beispiel eines HASH JOINs), aber anscheinend unvermeidlich: "It looks like that the generic implementation always generates a Parallel execution plan under the assumption for the final step that there is potentially another Parallel Slave Set active that needs to consume the data via re-distribution. This is a pity as it quite often implies unnecessary blocking operations as shown above."
  • die Verabeitungsreihenfolge für parallele Operationen entspricht nicht unbedingt der Reihenfolge, die für serielle Operationen gilt (und wo üblicherweise zuerst der im Plan am weitesten oben aufgeführte  Step ausgeführt wird, zu dem keine untergeordneten Steps existieren: also der erste Leaf-Step), da sich auch hier die Begrenzung auf zwei aktive parallel slave Gruppen auswirkt.
  • die BUFFER-Operationen aufgrund von blocking operations können zur Auslagerung auf die Platte führen, was natürlich der Performance schadet; auch ohne Auslagerung kann der Memory-Bedarf hoch sein.
  • Parallel Distribution Methods: Für den HASH JOIN (das übliche Join-Verfahren bei Parallelisierung) gibt es drei Verarbeitungs-Varianten, die in der Spalte "PQ Distrib" im Plan erscheinen:
    • Hash Distribution: die beiden Quelldatenmengen (row sources) werden über den Join-Key Hash-verteilt, was zwei aktive Slave-Gruppen erfordert, und der eigentliche Join wird wiederum von einer Slave-Gruppe durchgeführt, so dass sich (in der Regel) eine Buffered Operation ergibt
    • Broadcast Distribution: der Join (bzw. sein Probe Phase) wird zusammen mit einer der row source Operationen durchgeführt. Da keine Verteilung der Daten auf den Join-Key erfolgte, müssen die Ergebnisse der zweiten row source an alle Slaves, die den Join durchführen, weitergereicht werden (Broadcast). Dies führt zu einer Vervielfachung der intern verarbeiteten Datenmengen. Effizient ist das Verfahren, wenn die erste row source relativ klein ist.
    • Partition Distribution: wenn beide row sources in gleicher Weise partitioniert sind, ist ein partition-wise-Join möglich, der keine hash distribution der Daten erfordert, und deshalb von einer einzigen Slave-Gruppe ausgeführt werden kann und keine blocking operation hervorruft. Der partition-wise-Join ist damit das effizienteste der erwähnten Verfahren. Auch ohne Parallelisierung ist der partion-wise-Join sehr nützlich, da er die Größe der Join-Operationen reduziert.
  • MERGE JOIN und NESTED LOOPS sind ebenfalls parallelisierbar, kommen aber sehr viel seltener vor.
  • Für den partition-wise-Join sollte der DOP höchstens der Anzahl der Partitionen entsprechen.
  • mit Hilfe des Hints PQ_DISTRIBUTE lässt sich das Verhalten beeinflussen. Dabei lassen sich die Syntax-Details aus den OUTLINE-Informationen von DBMS_XPLAN entnehmen.
  • Der Abschnitt "Distribution of load operations" beschäftigt sich mit der Beeinflussung interner Sortierungen (z.B. zum Zweck einer möglichst effizienten Komprimierung)
  • "Plans Including Multiple Data Flow Operations (DFOs)" erläutert Fragen des geeigneten DOP und der Effekte einer Verknüpfung mehrerer Operationen mit unterschiedlichem DOP.

Keine Kommentare:

Kommentar veröffentlichen