Donnerstag, März 31, 2016

PL/SQL Fehlerbehandlung

Ja, es ist richtig: meine Einträge hier werden in letzter Zeit kürzer und kürzer. Daran werde ich aber auch heute nichts ändern, denn eigentlich will ich gerade nur einen Link unterbringen: Steven Feuerstein listet in seinem Artikel Nine Good-to-Knows about PL/SQL Error Management- nun ja: neun interessante Punkte auf, die man beim Exception Handling in PL/SQL berücksichtigen sollte. Zu den wichtigsten Hinweisen gehören aus meiner Sicht:
  • "An exception raised does not automatically roll back uncommitted changes to tables." Hier ist also immer noch eine explizite Entscheidung erforderlich (und möglich).
  • "Whenever you log an error, capture the call stack, error code, error stack and error backtrace." Dazu kann man dbms_utility-Prozeduren einsetzen.
Die anderen sieben Punkte sind aber auch nicht uninteressant.

    Donnerstag, März 24, 2016

    Begriffsbestimmung: deprecated und desupported

    Mike Dietrich erklärt die Unterschiede der Konzepte deprecated und desupported:
    Deprecated is a signal that something may disappear in the future and does not get enhanced anymore. No activity required except of taking note for your future plans. Desupported means that we don't fix anything anymore for a desupported feature or product - and it may even disappear. But often desupported features are still there and can be used on your own risk only.
    Diese Begriffe habe ich in der Vergangenheit mit Sicherheit auch eher unscharf verwendet.

    Sonntag, März 20, 2016

    Parameter Vorschläge in 12c

    Vor ein paar Wochen hatte Mike Dietrich (in seinem ausgesprochen lesenswerten Blog zu den Themen upgrades and migrations) einen Artikel mit interessanten Parameter-Vorschlägen für 12c veröffentlicht, diesen aber rasch wieder aus dem Verkehr gezogen, weil es anscheinend Oracle intern gewisse Unstimmigkeiten darüber gab, ob man z.B. den Einsatz von underscore Parametern (außerhalb von Support-Fällen) überhaupt als Lösungen für Performance-Probleme vorschlagen sollte. An Stelle dieses initialen Artikels (dessen Vorschläge mir ausgesprochen plausibel vorgekommen waren) hat der Herr Dietrich inzwíschen zwei neue Artikel geliefert, deren Vorschläge ich hier ohne umfangreichere Erläuterung wiedergebe:
    • Parameter Recommendations for Oracle Database 12c - Part I
      • _kks_obsolete_dump_threshold: dient zur Beschränkung der Größe von Dumps, die zur Analyse von cursor invalidations angelegt werden (und die sehr viel Platz rauben können).
      • _use_single_log_writer: die Verwendung mehrerer LGWR Prozesse ist ein neues Feature in 12c bringt aber offenbar unter Umständen einigen Ärger mit sich.
      • memory_target: das ist wirklich ein Klassiker: da der Parameter den Einsatz von HugePages verhindert und Probleme beim Upgrade hervorrufen kann, lautet die Empfehlung: "Avoid memory_target by any chance. Better use sga_target and pga_aggregate_target instead". Nachdem mir der Parameter in der Vergangenheit einigen Ärger gemacht hat, werde ich diese Empfehlung gerne häufiger zitieren.
      • pga_aggregate_limit: ist kein hartes Limit, wie Frits Hoogland gelegentlich gezeigt hat.
    • Parameter Recommendations for Oracle Database 12c - Part II
      • parallel_min_servers: hat in 12c einen neuen Default (nämlich CPU_COUNT * PARALLEL_THREADS_PER_CPU * 2 statt bisher 0).
      • job_queue_processes: die Anzahl der Slaves, die von den Job Schedulern (dbms_job, dbms_scheduler) verwendet werden. Da Oracle in 12c diese Jobs auch zur Statistik-Erfassung bei CTAS-Operationen verwendet, sollte der Wert gegenüber dem Default verringert werden (eher 2 * CPU cores als der Default 1000).
      • recyclebin: wenn man den Recyclebin nicht grundsätzlich deaktivieren will, sollte man ihn zumindest regelmäßig leeren (Vorschlag: einmal pro Woche), da er sonst im Dictionary allerlei Leichen hinterlässt. In älteren Releases konnten sich daraus unter anderem signifikante Zugriffsprobleme auf dba_free_space ergeben, die in 12c aber keine größere Rolle mehr spielen sollten.
      • deferred_segment_creation: sollte auf false gesetzt werden, sofern man nicht eine Applikation einsetzt, die zahllose ungenutzte Segmente erzeugt (Siebel, SAP, EBS).
    Ob die Serie noch um weitere Artikel ergänzt wird, weiß ich nicht, werde sie aber gegebenenfalls ergänzen.

    Dienstag, März 15, 2016

    Full Table Scan in umgekehrter Block-Reihenfolge

    Für mich völlig neu war der folgende Hinweis aus dem aktuellen Quiz-Artikel von Jonathan Lewis: mit Hilfe des - undokumentierten - Events 10460 kann man dafür sorgen, dass ein Full Table Scan des Blocks einer Tabelle in absteigender Reihenfolge liest, also beginnend mit dem letzten Block der Tabelle. Unter bestimmten Umständen könnte dieses veränderte Verhalten nützlich sein, etwa um ora-1555-Fehlern aus dem Weg zu gehen. Aber da das Event nicht dokumentiert ist, gehört das natürlich wieder zu den Dingen, die man nicht ohne Rücksprache mit Arzt oder Apotheker (sprich: die Oracle Support) einsetzen sollte.

    Mittwoch, März 09, 2016

    Falsche Ergebnisse durch Partitions-Operationen "without validation"

    Als Ergebnis einer Oracle-L-Diskussion hat Jonathan Lewis einen Artikel veröffentlicht, der einen Fall beschreibt, in dem der Einsatz eines Index-Hints ein falsches Ergebnis liefert, ohne dass dieses Verhalten als Oracle-Bug zu betrachten wäre. Während der Zugriff ohne den Index-Hint einen Full Table Scan mit Partition Pruning mit sich bringt, der die relevanten Daten nur aus der korrekten Partition liest, führt der Zugriff über den Index (ohne folgenden Tabellen-Zugriff) dazu, dass ein zusätzlicher Datensatz zurückgeliefert wird, der in der falschen Partition abgelegt wurde. Dass dies möglich war, ergab sich aus der Verwendung von Partition Exchange "without vaildation". Daher ist der Herr Lewis der Meinung, dass man sich schlecht über die inkonsistenten Ergebnisse beschweren kann, wenn man dem System vorher explizit die Anweisung gegeben hat, die Daten nicht zu überprüfen - und das scheint mir eine einleuchtende Position zu sein.

    Sonntag, März 06, 2016

    postgres: Analyse von page-Inhalten mit pageinspect

    Mit einer gewissen Regelmäßigkeit beklage ich mich darüber, dass postgres bei der Instrumentierung nicht ganz das Niveau der großen kommerziellen Konkurrenz erreicht. Einerseits ist das wohl nicht falsch, andererseits ist mir aber auch klar, dass mir da zum Teil auch einfach Informationen fehlen. In dieser Woche wurde ich beispielsweise auf die Extension pageinspect hingewiesen, mir deren Hilfe man in postgres die Inhalte der pages von Tabellen und Indizes untersuchen kann - also das Äquivalent zur Oracles Block-Dumps:

    (localhost:5433)postgres@postgres=# create extension pageinspect;
    CREATE EXTENSION
    
    Objekte in Erweiterung „pageinspect“
                Objektbeschreibung
    ------------------------------------------
     Funktion brin_metapage_info(bytea)
     Funktion brin_page_items(bytea,regclass)
     Funktion brin_page_type(bytea)
     Funktion brin_revmap_data(bytea)
     Funktion bt_metap(text)
     Funktion bt_page_items(text,integer)
     Funktion bt_page_stats(text,integer)
     Funktion fsm_page_contents(bytea)
     Funktion get_raw_page(text,integer)
     Funktion get_raw_page(text,text,integer)
     Funktion gin_leafpage_items(bytea)
     Funktion gin_metapage_info(bytea)
     Funktion gin_page_opaque_info(bytea)
     Funktion heap_page_items(bytea)
     Funktion page_header(bytea)
    (15 Zeilen)
    
    (localhost:5433)postgres@postgres=# create table t
    postgres-# as
    postgres-# select generate_series(1, 10) id;
    SELECT 10
    
    (localhost:5433)postgres@postgres=# SELECT * from heap_page_items(get_raw_page('t', 0));
     lp | lp_off | lp_flags | lp_len | t_xmin | t_xmax | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff | t_bits | t_oid
    ----+--------+----------+--------+--------+--------+----------+--------+-------------+------------+--------+--------+-------
      1 |   8160 |        1 |     28 |   1748 |      0 |        1 | (0,1)  |           1 |       2048 |     24 |        |
      2 |   8128 |        1 |     28 |   1748 |      0 |        1 | (0,2)  |           1 |       2048 |     24 |        |
      3 |   8096 |        1 |     28 |   1748 |      0 |        1 | (0,3)  |           1 |       2048 |     24 |        |
      4 |   8064 |        1 |     28 |   1748 |      0 |        1 | (0,4)  |           1 |       2048 |     24 |        |
      5 |   8032 |        1 |     28 |   1748 |      0 |        1 | (0,5)  |           1 |       2048 |     24 |        |
      6 |   8000 |        1 |     28 |   1748 |      0 |        1 | (0,6)  |           1 |       2048 |     24 |        |
      7 |   7968 |        1 |     28 |   1748 |      0 |        1 | (0,7)  |           1 |       2048 |     24 |        |
      8 |   7936 |        1 |     28 |   1748 |      0 |        1 | (0,8)  |           1 |       2048 |     24 |        |
      9 |   7904 |        1 |     28 |   1748 |      0 |        1 | (0,9)  |           1 |       2048 |     24 |        |
     10 |   7872 |        1 |     28 |   1748 |      0 |        1 | (0,10) |           1 |       2048 |     24 |        |
    (10 Zeilen)

    So weit war ich mit der Beispielerzeugung, ehe mir der Gedanke kam, mal nachzusehen, ob es dazu nicht schon entsprechendes Material gibt - und natürlich ist das der Fall: Michael Paquier hat in seinem Blog gelegentlich gezeigt, wie sich die Inhalte der pages einer heap Tabelle verändern, wenn man darauf DML-Operationen durchführt und vaccum stattfindet. Da auch die Dokumentation schon Beispiele enthält, spare ich mir die Erzeugung weiterer Standardfälle und belasse es bei den Links, die eine gute Grundlage für eine intensivere Beschäftigung darstellen würden.

    Nachtrag 27.12.2016: ein paar interessante Informationen zur Semantik der Spalten in den Analyse-Tabellen findet man hier.

    Dienstag, März 01, 2016

    Parallel DML und Buffered Operations

    In der letzten Woche musste ich in möglichst kurzer Zeit (und im zum Teil weiter laufenden Betrieb) eine größere Zahl von Aggregationstabellen neu aufbauen und möglicherweise hätte ich dabei Zeit sparen können, wenn ich bei der Abarbeitung meines Blog-Readers nicht so weit im Rückstand wäre. Immerhin hat Jonathan Lewis zuletzt ein Verhalten beschrieben, das mir unter Umständen ein paar Anregungen geliefert hätte. In seinem Beispiel erfolgte eine CTAS-Operation in 4 min, während eine entsprechende INSERT APPEND Operation 45 min erforderte. Den ersten Hinweis in diesem Zusammenhang lieferte (mal wieder) der Plan, in dem deutlich zu erkennen ist, dass zwischen den Schritten INSERT STATEMENT und LOAD AS SELECT keine PX Schritte zu finden sind - offenbar war hier parallel dml nicht aktiviert worden - und das war unter anderem auch etwas, was mir bei meinem Wiederherstellungseinsatz zunächst unterlaufen war. Im Beispiel des Artikels half die Parallelisierung des INSERTs allerdings nicht deutlich weiter: hier erschien nach der Aktivierung von parallel dml im Plan ein Schritt PX SEND RANDOM LOCAL, der darauf hin deutet, dass Oracle im Fall einer partitionierten Zieltabelle versucht, die Verwendung der Slaves möglichst effektiv an die Partitionsanzahl anzupassen. Ist die Anzahl der Slaves größer als die Anzahl der Partitionen, dann kann das PX SEND RANDOM LOCAL auftreten. Um das Verhalten zu ändern, kann man einen pq_distribute Hint einsetzen, der im Beispiel nicht nur den PX SEND RANDOM LOCAL Schritt (und das korrespondierende PX RECEIVE) beseitigt, sondern auch einen HASH JOIN statt eines HASH JOIN BUFFERED hervorruft. Damit konnte die Laufzeit auf 7 min reduziert werden.

    Tatsächlich hätte mir der Artikel aber vermutlich nur bedingt geholfen, da ich in der gegebenen Situation hauptsächlich versucht habe, die erforderlichen Operationen ohne größere Pausen und massivere Fehler über die Bühne zu bringen. Oder wie der Herr Lewis es ausdrückt: "but real-world DBAs don’t necessarily have all the time for investigations that I do." Jedenfalls nicht, wenn die Anwender warten.