Freitag, November 18, 2016

Granularität der SCN

Ich mache es mir immer leichter mit meinen Blog-Einträgen: diesmal beschränke ich mich auf einen Link zu einem Artikel von Frits Hoogland und zitiere dann einfach die dort gelieferte Zusammenfassung:
Changes in the database are synchronised by system change numbers, also known as SCNs. SCNs are the way Oracle serialises changes to data. However, this post shows that the Oracle engine tries to maximise the number of changes inside a SCN, and as such a SCN is not an highly granular serialisation mechanism. This is not a problem, since Oracle’s transactional protection mechanisms (like TX and TM locks) do work alongside SCNs to make sure no conflicting changes can happen at the same time. The changes itself do just read and pick the current global SCN from the instance, a commit of these changes does increase the global SCN, but as little as possible. You might find multiple changes in the same SCN, and you might even find commits with the same SCNs.
Sehr kompakt und präzise. Merken werde ich mir in erster Linie, dass der Artikel erklärt, warum mehrere Commits die gleiche SCN beinhalten können.

Mittwoch, November 16, 2016

dbms_redefinition und deterministische Funktionen

Vor längerer Zeit war ich hier zum Ergebnis gekommen, dass rdbms_redefinition für komplexere Umbaumaßnahmen nicht verwendbar ist, weil man im Mapping keine komplexere Join-Logik oder Subselects unterbringen kann. Jetzt habe ich bei Connor McDonald gesehen, wie man es richtig macht: statt eines Joins  kann man im col_mapping eine deterministische Funktion unterbringen - und damit wird das Package noch mal deutlich interessanter.

Dienstag, November 08, 2016

Delta-Bestimmung mit Oracle

Dani Schnider hat vor einigen Wochen einen schönen Artikel veröffentlicht, in dem er verschiedene Möglichkeiten zur Bestimmung von Datenänderungen zwischen Quellsystem und Data Warehouse erläutert. Grundsätzlich kann in solchen Fällen ein Full (oder Left) Outer Join verwendet werden, der die Daten aus Quelle und Ziel miteinander abgleicht, und dabei gibt es drei relevante Fälle:
  • ein Datensatz existiert nur in der Quelle und nicht im Ziel: demnach wurde er neu erzeugt und muss im Ziel ergänzt werden.
  • ein Datensatz existiert nur im Ziel, nicht aber in der Quelle: offenbar wurde er in der Quelle gelöscht. In der Regel wird er nicht aus der Zieltabelle gelöscht, sondern dort als "im Quellsystem gelöscht" markiert (in der Regel mit Zeitstempel).
  • ein Datensatz existiert in Quelle und Ziel, aber einige Attribute weichen ab. In diesem Fall können unterschiedliche Versionierungsstrategien verwendet werden.
Der angesprochene Full (Left) Outer Join wäre recht trivial, wenn es nicht Fälle gäbe, in denen einzelne Attribute NULL-Werte enthalten können. Für diese Fälle gibt es folgende Abgleichs-Möglichkeiten:
  • NVL: man ersetzt NULL-Werte durch einen Wert, der in den Daten nicht erscheinen kann - wobei auf den Datentyp zu achten ist. Die Definition entsprechender Default-Werte kann relativ mühsam sein.
  • LNNVL: ist Datentypunabhängig, hat aber den Nachteil, dass der Vergleich true liefert, wenn beide Werte NULL enthalten. Daher ist das für diesen Fall erzeugte Statement relativ unübersichtlich.
  • SYS_OP_MAP_NONNULL: eine interne Funktion, die NULL durch einen internen Platzhalter ersetzt. Dadurch wird die Vergleichsquery recht übersichtlich, aber leider ist die interne Funktion noch immer nicht offiziell dokumentiert.
  • DECODE: liefert 1, wenn die Vergleichswerte identisch sind oder beide NULL, sonst aber 1. Durch Aufsummieren der Vergleichsergebnisse kann man erkennen, ob es relevante Abweichungen gibt.
  • ORA_HASH: kann aus der konkatenierten Spaltenliste einen Hash-Wert generieren. Probleme kann die Länge der verknüpften Strings mit sich bringen und theoretisch gibt es die Möglichkeit von Hash-Kollisionen.

Mittwoch, November 02, 2016

Cost Based Optimizer-Grundlagen

Randolf Geist, dessen englischsprachige Artikel ich hier gerne exzerpiere, hat für die Zeitschrift "Informatik Aktuell" einen Beitrag Cost Based Optimizer: Grundlagen – mit Update für Oracle 12c geschrieben. Dem aufmerksamen Leser ist jetzt vielleicht schon aufgefallen, dass Zeitschrift und Artikel offenbar deutschsprachig sind. Das einziges, was ich dazu ergänzen möchte, ist, dass ich den Artikel für eine der besten einführenden Zusammenfassungen zum Thema halte, die ich bisher gelesen habe - und mir fällt nichts Vergleichbares ein, das in deutscher Sprache vorläge. Insofern werde ich vermutlich in Zukunft häufiger auf diesen Artikel verweisen.

Mittwoch, Oktober 26, 2016

Angemessene Indexgröße

Für All Things Oracle hat Jonathan Lewis vor einigen Wochen einen Artikel geschrieben, in dem er erläutert, wie man die angemessene Größe eines B*Tree Index bestimmen kann. Darin geht er davon aus, dass ein stabiler B*Tree Index in der Regel etwa 70% des verfügbaren Speichers in den Leaf-Blocks auslastet, während etwa 30% freier Speicher in den Leaf-Blocks verfügbar bleibt. Unter dieser Voraussetzung ist es möglich eine grobe Abschätzung zu geben, wie groß ein Index in etwa sein sollte - und daraus kann man dann ableiten, ob unter Umständen einer der seltenen Fälle vorliegt, in denen ein Index-Rebuild tatsächlich einmal eine gute Idee sein könnte. Seine Formel zur Berechnung der angemessenen Indexgröße enthält folgende Elemente:
  • sum(user_tab_cols.avg_col_len + 1) für alle Index-Spalten
  • 6 byte für die rowid (8 byte im Fall eines globally partitioned index)
  • 1 byte, wenn der Index non-unique ist
  • 2 byte pro row
  • 2 byte pro row directory Eintrag
Der im Leaf-Block verfügbare Platz wird berechnet als: Blöckgröße - 200 Byte (für das block directory) und muss den pctfree-Wert berücksichtigen. Damit kann man dann berechnen, wie viele Index-Einträge in einen Leaf-Block passen und wie groß der Index insgesamt sein muss. Die Formel sollte für nicht komprimierte Indizes nicht mehr als 1 oder 2% von der tatsächlichen Index-Größe nach einem rebuild abweichen - und auf seiner Webseite hat der Herr Lewis auch ein entsprechendes Skript bereitgestellt.

Ein klassischer Fall, in dem ein Index von einem rebuild profitieren kann, ist ein fifo (first in first out) Processing, bei der einzelne Einträge stehen bleiben - und da ein Index-Block erst wieder verfügbar wird, wenn alle Einträge daraus gelöscht wurden, machen solche Überbleibsel Probleme. Solche Fälle kann man recht komfortabel mit dem dbms_space-Package analysieren und auch zu diesem Zweck gibt es ein Skript beim Herrn Lewis.

Ein weiteres Hilfsmittel zur Analyse von Indizes ist der Treedump den man über ein trace event erstellen lassen kann. Das Vorgehen dabei und einige grundlegende Analysetechniken (etwa die Verwendung von grep) werden im Artikel erläutert, aber in diesem Fall spare ich mir die detaillierte Nacherzählung. Festzuhalten bleibt, dass der Treedump eine genauere Analyse der Index-Struktur erlaubt und es möglich macht, ungewöhnliche Fälle exakter zu bestimmen.