Freitag, Mai 26, 2017

Semantik des parallel(n) Hints

Jonathan Lewis weist in seinem Blog darauf hin, dass der Hint /*+ parallel(n) */ keineswegs einen parallen Plan erzwingt, auch wenn eine ausreichende Anzahl an parallelen Ausführungsprozessen zur Verfügung steht. Tatsächlich weist der Hint den Optimizer nur dazu an, die Kosten der parallelen Ausführung für jeden überprüften Plan zu berücksichtigen - aber letztlich wählt der Optimizer den Plan mit den niedrigsten Kosten (sofern kein Bug im Spiel ist) und das kann durchaus ein serieller Plan sein.

Dazu liefert der Artikel ein Beispiel dafür, wie sich das Verhalten zwischen unterschiedlichen Releases verändern kann: für die Beispielquery eines (eindeutigen) id-Zugriffs liefert 11.2.0.4 auch bei Verwendung eines parallel(4)-Hints einen seriellen Plan, was beim Index-Zugriff auf einen einzelnen Datensatz durchaus verständlich ist. Erst wenn man den Zugriff mit einem zusätzlichen FULL-hint ergänzt, ergibt sich die Parallelisierung. In 12.2.0.1 sieht das Verhalten anders aus: dort erscheint ein PX SELECTOR im Plan, der eine hash distribution über Blockadressen ermöglicht, was im Fall globaler Indizes in partitionierten Tabellen hilfreich sein könnte. Das Phänomen hat Jonathan Lewis bereits vor knapp einem Jahr in einem anderen Artikel beschrieben.

Mittwoch, Mai 17, 2017

Online Partitionierung einer existierenden Tabelle in 12.2

Eine sehr schöne Ergänzung der Partitionierungs-Optionen in 12.2 beschreibt Maria Colgan in ihrem Blog: die Möglichkeit, eine nicht partitionierte Tabelle ohne downtime - also online - in eine partitionierte Tabelle umzuwandeln. Die Syntax dazu sieht etwa folgendermaßen aus:

alter table t
partition by ...
(
   partition p1 ...,
   partition p2,
 ...
)
update indexes online

Das sieht für mich sehr intuitiv und vor allem kompakt aus. Dabei dient "update Indexes" wie üblich dazu, die Indizes während des Aktualisierungsvorgangs verfügbar zu halten. Die Default-Optionen bei der Umwandlung der Indizes sind folgende:
  • Indizes, die bereits als "global partitioniert" angelegt wurden, behalten ihr Partitionierungs-Schema
  • Indizes, die nicht mit dem "partition key" starten, werden "global non-partitioned indexes"
  • Indizes, die mit dem "partition key" starten, werden lokal partitionierte Indizes
  • Bitmap Indizes werden zu lokal partitionierte Indizes
Dass man diese Default-Optionen überschreiben kann, ist bei Frau Colgan nur implizit angedeutet (nämlich durch die Verwendung des Terminus "default"), aber Richard Foote hat dazu vor kurzem ein Beispiel veröffentlicht: auf das "update indexes" folgen dann in Klammern die Spezifikationen der Konvertierung.

Eine zweite nützliche Ergänzung zur Partitionierung in 12.2 ist die Möglichkeit, die Basis-Tabelle für eine "partition Exchange" Operation mit einem Befehl "create table ... for exchange with table ..." anzulegen. Allerdings scheint dieses Kommando nicht zur automatischen Generierung der passenden lokalen Indizes zu dienen, so dass hier weiterhin eine gewisse Sorgfalt bei der Vorbereitung des partition exchange erforderlich bleibt - was aber insofern kein größeres Problem darstellt, als der Austausch von Partitionen aus meiner Sicht ohnehin ein Task ist, der verskriptet werden sollte.

Darüber hinaus erwähnt die Autorin noch eine dritte nützliche Ergänzung: die Einführung von interval partitioning für List-partitionierte Tabellen. Dabei hoffe ich, dass die Intervall-Partitionierung in 12.2 stabiler geworden ist, als sie das in früheren Releases geworden ist, aber das ist ein Thema, das im Artikel nicht angesprochen wird - und dem im Detail nachzugehen mir aktuell die Zeit fehlt.

Freitag, April 21, 2017

postgres Statistiken: pg_stat_all_tables

Alexey Lesovsky hat bereits eine ganze Reihe interessanter Artikel im Rahmen einer Serie "Deep dive into postgres stats" veröffentlicht. Bisher hatte ich mich davor gedrückt, diese Ausführungen zusammenzufassen, aber heute ist ein ruhiger Tag und die pg_stat_all_tables scheint mir eine besonders interessante Quelle zu sein...

Die View pg_stat_all_tables enthält eine ganze Reihe interessanter Informationen zur Nutzung von Tabellen. Unter anderem weist sie hin auf:
  • Zugriffsinformationen: die View enthalt Informationen zur Anzahl sequentieller Scans (also Full Table Scans, wie man sie in anderen RDBMS nennt) und zur Anzahl von Index-Zugriffen sowie zur Anzahl der dabei zurückgelieferten Datensätze. Eine hohe Zahl sequentieller Scans auf großen Tabellen deutet häufig auf fehlende Indizes hin. Weiterhin könnten Index-Zugriffe mit hohen durchschnittlichen Satzanzahlen auf wenig selektive Index-Zugriffe hindeuten.
  • Schreiboperationen: zeigt die Menge der DML-Operationen auf den Tabellen. Dabei wird zwischen Standard- und HOT-(=Heap-only tuples) Updates unterschieden, wobei letztere wünschenswert sind, da sie Indizes nicht aktualisieren, wenn ein Update keine inidzierten Werte verändert. Allerdings funktionieren HOT-Updates nur, wenn die zugehörige page ausreichend Platz übrig hat. Für Tabellen, bei denen sich HOT-Updates kaum ergeben, könnte eine Anpassung des Fillfactors sinnvoll sein (der nur für neue Datensätze berücksichtigt wird, den Platzverbrauch des Objekts vergrößert und in diesem Zusammenhang nur dann relevant ist, wenn es tatsächlich updates ohne Bezug auf indizierte Spalten gibt).
  • die autovacuum queue: seit 9.6 kann man bestimmte Informationen zum autovacuum aus der View pg_stat_progress_vacuum bekommen. Was fehlt ist allerdings weiterhin eine Liste der Tabellen, für die aktuell ein vacuum-Lauf erforderlich wäre. Dazu hat der Autor eine komplexe Query (die unter anderem auf pg_stat_all_tables zugreift) bereitgestellt, mit deren Hilfe sich die Länge der autovacuum queue bestimmen lässt. Basierend auf den Aussagen der Query kann man dann über Maßnahmen zur Optimierung des autovacuum nachdenken (Erhöhung der autovacuum_max_workers oder Anpassung anderer autovacuum-Parameter).
Im Vergleich zu dem, was andere RDBMS an internen Statistiken liefern, sind die Informationen bei postgres überschaubar, erlauben aber durchaus interessante Analysen.

Dienstag, April 18, 2017

postgres Extensions

Zwei interessante Hinweise findet man im neusten postgres-Artikel von Daniel Westermann:
  • das data dicitionary von postgres liefert zahlreiche Informationen zu den verfügbaren und den installierten Extensions:
    •  pg_available_extensions: zeigt die verfügbaren und die installierten Extensions inklusive eines Kommentars zu ihrer Funktion.
    • pg_available_extension_versions: liefert weitere Detailinformationen zu den Extensions, unter anderem zu den Abhängigkeiten, die zwischen den Erweiterungen bestehen.
    • pg_extension: liefert Informationen zu den installierten Extensions. Dabei weichen die Informationen von denen ab, die der psql-Shortcut \px liefert.
  • beinahe ebenso interessant ist der zweite Hinweis, den der Herr Westermann liefert: mit dem Switch: "\set ECHO_HIDDEN on" kann man die den psql-Shortcuts zugrunde liegenden Befehle anzeigen lassen. Mir war zwar klar, dass das irgendwie möglich sein sollte, aber bisher hatte ich mir nie die Mühe gemacht, nach dieser Option zu suchen.

Donnerstag, April 06, 2017

Skript zur Bestimmung von Index Fragmentation

In den OTN Foren gibt es bei diversen Beiträgern eine gewisse Tendenz dazu, auf bestimmte Schlüsselwörter allergisch zu reagieren. Eines dieser Schlüsselwörter ist: Fragmentation. Im ungünstigen Fall bekommt man dann zur Antwort, dass es so etwas wie Fragmentation nicht gäbe - was ich für ausgemachten Blödsinn halte -, im günstigeren Fall, dass man den Terminus bitte erst mal definieren sollte, was durchaus eine sinnvolle Reaktion darstellt. Aber da der Fall von Index Fragmentation eher weniger kontrovers ist, belasse ich es hier bei der harmlosen Einordnung: ein Index ist dann fragmentiert, wenn er deutlich mehr Leaf Blocks beinhaltet als zur Speicherung der enthaltenen Einträge eigentlich erforderlich wären. Bei Kellyn Pot’Vin-Gorman habe ich heute einen Verweis auf ein nützliches Skript von Franck Pachot gefunden, das Folgendes leistet: "shows the number of rows per block, as well as used and free space per block, and aggregates that by range of values". Für die Detail-Analyse einzelner Indizes kann dieses Skript extrem nützlich sein - und die manuelle Sammlung und Verknüpfung der entsprechenden Informationen vermeiden.