Mittwoch, Oktober 31, 2018

Indizierung von Foreign Keys in Oracle und Postgres

Dass nicht indizierte Foreign Keys in Oracle massive Locking-Probleme hervorrufen können, habe ich vermutlich zum ersten Mal vor mehr als 15 Jahren bei Tom Kyte gelesen (ohne dass ich dazu gerade eine passende Textstelle liefern könnte). Franck Pachot hat jetzt darüber geschrieben, wie das Verhalten unter entsprechenden Bedingungen in Postgres aussieht - eine Frage, die eigentlich auf der Hand liegt, der nachzugehen mir bisher aber noch nicht in den Sinn gekommen war. Das Ergebnis lautet: bei Postgres ist die Indizierung der Foreign Keys nicht zur Vermeidung von Locks erforderlich, sondern nur zur Optimierung der Navigation von Parent zu Child. Grundlage dieses Verhaltens ist die Verfügbarkeit von "shared row locks" in Postgres (die es in Oracle nicht gibt). Die Details der Erklärung erzähle ich hier nicht nach - mir genügt die Erinnerung, dass beide RDBMS sich in diesem Punkt unterschiedlich verhalten.

Montag, Oktober 08, 2018

Transport von SQL Patches

Marco Mischke erläutert in seinem Blog, dass "SQL Patches" bei einer Migration mit Hilfe von "data pump" nicht transportiert werden, da sie nicht zum Schema der Applikation gehören. Das Package DBMS_SQLDIAG enthält aber Prozeduren, mit deren Hilfe man die Patches in einer Tabelle ablegen kann, die sich dann ihrerseits mit "data pump" transportieren lässt. Das ist also kein besonderes Hindernis, aber ein Punkt, den man im Rahmen einer Migration im Auge behalten muss.

Donnerstag, Oktober 04, 2018

Performance von lokalen und globalen Indizes partitionierter Tabellen

Richard Foote hat eine neue Artikel-Serie gestartet, in der er sich mit der Performance lokaler und globaler Indizes für partitionierte Tabellen beschäftigt. Da ich auch zu den Leute gehöre, die globale Indizes weitgehend vermeiden, finde ich Argumente, die für die globalen Indizes sprechen, grundsätzlich interessant:
  • “Hidden” Efficiencies of Non-Partitioned Indexes on Partitioned Tables Part I (The Jean Genie): liefert ein sehr einfaches initiales Beispiel: eine Tabelle enthält Daten für acht Jahre und einen Index für die Spalte TOTAL_SALES, die für den Wert 42 insgesamt 10 Datensätze liefert. Bei Verwendung einer nicht partitionierten Tabelle erfordert ein Zugriff auf diese 10 Datensätze 14 consistent gets (4 für den Durchgang durch die Indexstruktur und 10 für die Datensätze) - und die gleichen 14 LIOs sind auch erforderlich, wenn man nur einen Datensatz für ein bestimmtes Jahr auswählt, da die Datumsangabe nicht Teil des Index ist und daher erst bei der Filterung berücksichtigt wird. Für den globalen Index auf einer partitionierten Tabelle ergeben sich die gleichen 14 LIOs für Fall 1, aber für den zweiten Fall sinkt die Zahl der LIOs auf 5, da hier für den Optimizer klar ist, dass nur die Partition des fraglichen Jahres den gewünschten Datensatz enthalten kann - es erfolgt also ein "partition pruning".
  • “Hidden” Efficiencies of Non-Partitioned Indexes on Partitioned Tables Part II (Aladdin Sane): bis zu Oracle 8 bestand die rowid grundsätzlich aus 6 byte und enthielt "file number", "block number" und "row number". Seit der Einführung des Partitioning in Oracle 8 kann ein partitioniertes Objekt in mehreren Tablespaces abgelegt werden, was dazu führte, dass die "file number" nicht mehr eindeutig war. Daher wurde die rowid für globale Indizes um die "data object id" erweitert (und damit auf 10 byte erweitert). Diese zusätzliche Information macht das "partition pruning" möglich, da der Index in jedem einzelnen Schlüssel die dafür erforderliche Information enthält.
  • “Hidden” Efficiencies of Non-Partitioned Indexes on Partitioned Tables Part III” (Ricochet): weist darauf hin, dass ein lokaler Index durch die kürzere rowid (ohne die "data object id" und daher nur 6 byte lang) etwas kleiner ist als ein entsprechender globaler Index. Für einen Zugriff, der sich auf eine Partition beschränkt, ist der lokale Index daher etwas effizienter als der globale Index (4 vs. 5 LIOs). Beim Partitions-übergreifenden Zugriff ist der globale Index dagegen deutlich effizienter, da sich das Lesen auf eine Index-Struktur beschränkt und nicht über mehrere interne Indizes erfolgen muss.
  • “Hidden” Efficiencies of Non-Partitioned Indexes on Partitioned Tables Part IV” (Hallo Spaceboy) : zeigt, dass man das BLEVEL eines globalen Index dadurch reduzieren kann, dass man ihn partitioniert (nach einer anderen Spalte als dem partition key).
Wie üblich gilt, dass ich die folgenden Artikel ergänzen werde, wenn ich nicht die Lust daran verliere.

    Montag, Oktober 01, 2018

    Overhead für Extended Trace im SQL Server

    Da ich ein großer Freund des Tracings von Datenbank-Operationen bin, finde ich Untersuchungen wie die von Nenad Noveljic zum Thema "SQL Server Extended Events Trace Overhead" sehr interessant. Im Artikel wird ein Testszenario vorgestellt, das eine relativ zweckfreie Schleife zunächst ohne und dann mit dem Event "sql_batch_completed" gegenüberstellt. Für diese stark CPU-hungrige Operation ergibt sich eine Verlangsamung um ca. 15% nach der Aktivierung des Events: die Laufzeit steigt von 61 auf 74 Sekunden - wobei die Erhöhung auf CPU-Last zurückzuführen ist, die nicht in den Event-Statistiken enthalten ist (sondern in sys.dm_exec_requests.cpu_time). Andere Events - wie etwa logout - haben nahezu keine Auswirkungen auf die Performance. Ein entsprechender Test mit Oracle und einem 10046er Trace zeigt keine entsprechende Wirkung - wobei allerdings anzumerken wäre, dass dort ein Trace mit rowsource statistics unter Umständen recht massive negative Effekte hervorrufen kann, wie Jonathan Lewis gerade mal wieder in Erinnerung gerufen hat.