Mittwoch, Januar 16, 2013

Compression in Oracle

Jonathan Lewis hat mit einer Artikelserie zum Thema Compression in Oracle für redgates großartige All Things Oracle Seite begonnen. Hier ein paar Punkte daraus, die mir besonders erinnerungswürdig erscheinen (aber kein vollständiges Exzerpt darstellen sollen):

Compression in Oracle – Part 1: Basic Table Compression
  • enthält eine Testreihe mit diversen unterschiedlichen Operationen, die zeigt, dass basic compression nur bei direct path operationen (CTAS, INSERT APPEND, ALTER TABLE ... MOVE) wirksam ist und dass sie implizit den pctfree-Wert auf 0 setzt.
  • basic (und OLTP) compression führen eigentlich keine compression, sondern eine deduplication durch, indem sie wiederholte token im block in Symboltabellen speichern und dann darauf referenzieren.
  • Oracle kann die Reihenfolge der Werte im Block umstellen und mehrere Elemente in einer Kombination zusammenfassen, um die Komprimierung zu verbessern - "Oracle can rearrange the order that the columns are stored in this block to put those tokens side by side, and create a new token the represents the combination of the two individual tokens". Solche Umstellungen der Spaltenreihenfolge sind in der Angabe "perm_9ir2[4]={ 2 0 1 3 }" im Block dump sichtbar: "for this block Oracle has rearranged (permuted) the order the columns are stored so that the thing stored at column 2 in this block is column 0 in the table definition, column 0 is really column 1, column 1 is column 2 and column 3 is (still) column 3".
  • in den row-informationen des block dumps kann man die Wirkung der compression in der Differenz zwischen der Angabe tl (= total length) und den Angaben der Spaltenlänge + 1 lock byte + 1 flag byte + 4 byte für die 4 column length Angaben + 1 byte column count (cc) erkennen. Im Beispiel beträgt die tl tatsächlich nur 5 byte, die die bindmp (bind map) Angabe enthalten: "These five bytes are the flag byte (0x2c = ‘–H-FL’), the lock byte, the “stored” column count – i.e. the number of columns stored at this location, which is just one – and the next two bytes tell us that that one “column” is a token representing 4 consecutive and we need to look at token 0×31 of the token table".
  • im Beispiel verweist die bindmp-Angabe wiederum auf weitere (sub)token und enthält auch Angaben zur Anzahl der Verwendung von token (also zur Häufigkeit der Ersetzungen).
  • für das Lesen der Spalten-Werte ist somit keine decompression erforderlich, Oracle "simply re-constructs the row you need by hopping back and forth between the row directory and the row pieces (the code may even avoid visiting some tokens – the single column ones – if the column values aren’t needed for the SQL statement)".
  • das Springen zwischen den token ist CPU-intensiv. "As a side effect, because Oracle will have to hold (pin) the block for some time to reconstruct rows, you may find that your code will do fewer “consistent gets – examination” which means more activity on the “cache buffers chains” latch. Of course, we hope that the extra CPU time will be offset by the smaller number of physical reads we may have to do because we’ve packed our rows into a smaller number of blocks, which may allow us to keep more data cached for longer."
  • beim Löschen eines Satzes müssen zusätzlich die Angaben zur Häufigkeit der Verwendung eines Komprimierungs-Tokens korrigiert werden: der Aufwand von DELETEs ist demnach im Fall komprimierter Tabellen größer als in Fällen ohne Komprimierung.
  • es kann vorkommen, dass ein nicht mehr verwendetes Token mit der Verwendungshäufigkeitsangabe 0 im Block stehen bleibt.
  • UPDATEs führen zur Deaktivierung der compression für den veränderten Satz (also zu einer row expanison) - allerdings nur, wenn das UPDATE komprimierte Attribute betrifft. Ein Rollback bringt einen solchen Satz allerdings wieder zurück in den komprimierten Zustand.
  • Oracle lässt trotz PCTFREE = 0 einige Byte pro Block für minimale Reorganisationsoperationen frei. Für moderate UPDATE-Häufigkeiten wäre ein PCTFREE-Wert > 0 sinnvoll.
  • seit 11.2.0.3 sollte ein Update, das keine tatsächliche Änderung darstellt, auch keine expansion ausführen. Allerdings scheint das nicht immer zu funktionieren.
  • OLTP compression lässt den Standardwert für PCTFREE stehen (also in der Regel 10)
  • sie wirkt (erwartungsgemäß) auch bei conventional path operations
  • die Statistiken zum Thema heap block compress haben eigentlich nicht unmittelbar mit dem Feature compression zu tun, sondern zählen, wie häufig der free space im Block reorganisiert wurde (und die row pieces zum Ende des Blocks hin verschoben wurden).
  • die Anzahl der heap block compress Operationen ist im Beispiel deutlich höher als die Blockanzahl, was ein Hinweis darauf ist, dass jeder Block mehrfach reorganisiert werden muss
  • die compression erfolgt sukzessive, wenn neue Einfügeoperationen Platz benötigen. Dabei wird der neu hinzugefügte Satz, der die Operation auslöst, selbst nicht komprimiert.
  • reine Update-Operationen triggern die OLTP compression nicht, wie Randolf Geist gelegentlich gezeigt hat.
  • OLTP compression "doesn’t compress for all operations, it compresses only for inserts, and the benefits it has over basic compression are that (a) it leaves 10% of the block free for updates, and (b) it doesn’t require direct path inserts to trigger compression. Given the limitations on how it works you may find that the problems it brings might make it something you want to avoid."
  • der Komprimierungseffekt für OLTP compression ist (etwas) niedriger als der für direct path compression.
  • index compression betrifft nur die führenden Index-Spalten.
  • die Informationen im row heap eines Index-Blocks sind nicht (notwendigerweise) sortiert (können es temporär aber sein): die Sortierung liegt nur im row directory vor.
  • die Komprimierung ist eine Deduplizierung der n führenden Spalten.
  • anders als im Fall der table compression kann ein token im Fall der index compression nur an der passenden Stelle (= Spalte) verwendet werden.
  • im block dump erscheinen für die dedulizierten token prefixes: "each takes 7 bytes (len = 7) consisting of the flag byte (flag:) that shows it’s a prefix entry, a lock byte (that never seems to get used) and, for each column (and there is only one), a length byte and the four bytes that make up the prefix". Dazu kommt eine Angabe prc: "(possibly “prefix usage count”) reporting the number of suffixes associated with this prefix."
  • für den Rest des Index-Eintrags findet sich die Angabe "psno (possibly “prefix sequence number”), that tells us which prefix the suffix belongs to; again this item is derived, not something stored with the row."
  • die byte Adresse eines Index-Eintrags erscheint in Brackets [...] hinter der row#-Angabe. Diese Angaben erscheinen (als hex Werte) im row directory (in umgekehrter Reihenfolge). Dort finden sich auch die Angaben zu den Startwerten der deduplizierten token (ebenfalls in umgekehrter Reihenfolge). Aus den Angaben kann Oracle die prc- und psno-Werte ableiten.
  • zeigt, dass bereits ein Präfix von nur einem Byte Länge zu sinnvoller compression führt, sofern es pro Präfix in der Regel mindestens vier Datensätze gibt (was anhand eines Beispiels belegt und theoretisch erklärt wird: pro Satz werden zwei Byte eingespart(Inhalt + Length Byte), was gegen den Overhead von prefix (4 Byte) und prefix directory (4 Byte) zu rechnen ist).
  • eine Reduzierung der Index-Größe kann allerdings höhere contention für einzelnen Index-Blocks hervorrufen.
  • beim Select ist der Overhead größer, wenn es sehr viele Präfixe und nur wenige zugehörige rows gibt. Insgesamt ist er aber in der Regel nicht signifikant (diese Einschätzung deckt sich mit meinen Erfahrungen).
  • durch die Compression ändert sich das Costing des Index (da darin die LEAF_BLOCKS eine zentrale Komponente sind): ein komprimierter Index kann dadurch interessanter werden als ein anderer nicht komprimierter Index, der bis dahin die erste Wahl des CBO gewesen ist.
  • für DML-Operationen müssen im komprimierten Index zusätzliche Änderungen durchgeführt werden (Aktualisierung des prefix directory (usage counter) und der zugehörigen row). Für DML-Operationen ist der Overhead der Compression deutlich größer als im Fall von Select-Zugriffen.

Keine Kommentare:

Kommentar veröffentlichen