Donnerstag, Dezember 18, 2014

SDSQL

In der Vergangenheit habe ich schon häufiger erwähnt, dass ich den SQL Developer für ein sehr brauchbares Werkzeug halte, das mit erstaunlichem Tempo weiterentwickelt wird - insbesondere, wenn man bedenkt, dass es ganz und gar kostenlos ist. Fast noch interessanter finde ich aber das vor wenigen Tagen vorgestellte zugehörige Tool SDSQL, das die sqlplus engine des SQL Developers als command line interface verfügbar macht - und zahlreiche Features hinzufügt, die im klassischen sqlplus fehlen. Die beste Informationsquelle zum Thema ist zur Zeit der Blog von Kris Rice (der auch auf Twitter sehr aktiv ist), in dem sich unter anderem der einführende Artikel What is SDSQL? findet, in dem nicht nur die titelgebende Frage beantwortet wird, sondern auch download-Quelle und Installations-Verfahren erwähnt werden - wobei die Installation unter Umständen nicht ganz reibungslos abläuft, wie man auch in einigen OTN-Threads erfährt. Auf meinem Rechner hatte ich Probleme mit der TNS-Namensauflösung und musste host naming verwenden. Außerdem ist es derzeit noch recht einfach, die Beta-Version 4.1 zum Absturz zu bringen. Aber einige der in weiteren Artikeln vorgestellten Features haben großen Potential, so etwa:
  • die History-Funktion, die über den Buchstaben h aufgerufen wird und eine Liste der letzten (bis zu 100) Queries liefert. Mit "history full" kann man die Historie in der ursprünglichen Formatierung abrufen und "history usage" informiert über die Häufigkeit der Verwendung von Befehlen.
  • das ddl-Kommando, das einen Shortcut auf die Objekt-Informationen aus dbms_metadata darstellt. Im Artikel wird auch gezeigt, wie sich die dbms_metadata-Ausgabe mit Hilfe von set_transform_param-Aufrufen an die eigenen Vorstellungen anpassen lässt (um etwa die Storage-Informationen zu unterdrücken).
  • die Alias-Funktion, mit der man ein Makro erstellen kann - also etwa den Alias "Sessions" für ein Select auf v$session. Außerdem zeigt der Artikel eine erschütternd simple Create Table as Select (=CTAS)-Syntax zum Kopieren von Tabellen, nämlich: ctas emp emp_new.
  • die Definition von precommand und postcommand Kommandos zur Ausführung rahmender SQL-Aufrufe - etwa zur Erfassung von Ausführungsstatistiken für eine Query (aus v$mystat).
Die Liste wird sicherlich noch wachsen. Und wenn die Stabilitätsprobleme behoben sind - bzw. wenn ich gelernt habe, welche Operationen ich mir sparen sollte -, wird das sicher ein ausgesprochen wertvolles Werkzeug; vielleicht wird es bei mir gar die Stelle von sqlplus einnehmen, auch wenn der Gedanke mich beinahe erschreckt...

Ob ich die weiteren Artikel von Kris Rice regelmäßig ergänzen werde, weiß ich noch nicht - der Mann ist erschütternd produktiv.

Gerade sehe ich, dass Jeff Smith gestern auch noch einen Artikel zur Installation veröffentlicht hat, in dem erklärt wird, wie man sich auch mit TNS erfolgreich verbinden kann.

Dienstag, Dezember 16, 2014

Blockgröße und Multi-Row-DML

Nikolay Savvinov hat vor einiger Zeit einige Artikel veröffentlicht, die sich damit beschäftigen, dass DML-Operationen für Blocks einer Größe von 4K eine deutlich schlechtere Performance liefern als entsprechende Operationen für Blocks der Standardgröße (8K). Hier eine Liste der Artikel:
Ich spare mir eine detaillierte Zusammenfassung der Artikel und springe gleich zur Pointe, die der Titel des letzten Artikels bereits andeutet - das Verhalten folgt einer inneren Logik, die aber offenbar nicht dokumentiert ist: wenn die potentielle Satzlänge (also die Addition der definierten Spaltenlängen) die Blockgröße überschreitet, dann schaltet Oracle automatisch in einen row-by-row Modus um und verzichtet auf die Bulk-Operation, was dann (unter anderem) zu größerer Redo-Generierung und schlechterer Performance führt. Ich konnte das Verhalten mit einem angepassten Test auch für 8K-Blöcke nachvollziehen - es scheint sich also um ein allgemeines Phänomen zu handeln. Dieses Verhalten kann als Argument gegen die Verwendung unnötig breiter Spalten "auf Verdacht" für den Fall unerwartet großer Werte betrachtet werden.

Donnerstag, Dezember 11, 2014

OPTIMIZER_DYNAMIC_SAMPLING Level 11 und Ergebnisspeicherung

Der Optimizer ist ein komplexes Stück Software und wird im Lauf der Zeit immer komplexer. Mit Oracle 12c und insbesondere mit 12.1.0.2 sind weitere interne Komponenten ins Spiel gekommen, die einen Einfluss auf seine Entscheidungen nehmen. Seit grauer Vorzeit gibt es Stored Outlines, auch schon seit längerer Zeit SQL Profiles, daneben dann SQL Pan Baselines (und die SPM Infrastruktur) und SQL Patches. In 12c wurden einige Komponenten umbenannt und funktional erweitert: aus dynamic sampling wurden dynamic statistics, aus cardinality feedback wurde statistics feedback und neu dazu kamen SQL Plan Directives. Stefan Koehler hat gelegentlich versucht, ein wenig Ordnung in diese Sammlung unterschiedlicher Instrumentarien zu bringen und dabei neben umfassenden Auszügen aus der Dokumentation und entsprechenden Links auch ein ziemlich umfangreiches Beispiel zum Zusammenspiel der Komponenten ergänzt und darin insbesondere die Rolle der SQL Plan Directives beleuchtet (die den Optimizer anweisen, dynamic sampling durchzuführen und unter Umständen extended statistics anzulegen, was die Direktive dann überflüssig machen kann - wie hier ausgeführt). Ich vermute, dass das Zusammenspiel dieser Komponenten sehr viele seltsame Effekte mit sich bringen kann; der ein oder andere Bug würde mich auch nicht überraschen - schon die Erstellung einer Matrix zum Vorrang bzw. zur kombinierten Verwendung der Hilfsmittel dürfte eine komplexe Aufgabe sein...

Aber genug der allgemeinen Vorrede: im Rahmen eines OTN-Threads wurde mir zuletzt klar, dass ich keine klare Vorstellung davon habe, wie sich dynamic sampling (oder dynamic statistics) mit dem in 12.1.0.2 eingeführten neuen Level 11 bezüglich ihrer Persistierung verhalten. Dass es eine Persistierung gibt behauptet dabei die Dokumentation in ihrer Beschreibung der Parameterangaben: "Level 11: use dynamic statistics automatically when the optimizer deems it necessary. The resulting statistics are persistent in the statistics repository, making them available to other queries." Da ich keine Informationen dazu finden konnte, was ich mir unter diesem "statistics repository" vorstellen sollte, habe ich dazu einen kleinen Test durchgeführt:

-- 12.1.0.2
drop table t;

create table t
as
select rownum id
     , case when rownum <= 100 then 1 else 0 end col1
  , lpad('*', 50, '*') padding
  from dual  
connect by level <= 100000;  

create index t_idx on t(col1);

alter session set OPTIMIZER_DYNAMIC_SAMPLING = 11;

exec dbms_monitor.session_trace_enable();

-- query execution
select count(*) from t where col1 = 1;

alter system flush shared_pool;

-- repeated query execution
select count(*) from t where col1 = 1;

exec dbms_monitor.session_trace_disable()

Im erzeugten Trace-File erscheinen dabei vor beiden Ausführungen dynamic sampling Queries, die am Kommentar /* DS_SVC */ zu erkennen sind. Zum Teil können die Ergebnisse aus dem result cache genommen werden, in anderen Fällen sind "echte" Leseoperationen erforderlich - aber in jedem Fall müssen die Daten erneut ermittelt werden und im Trace finden sich keine Hinweise auf eine Persistierung der Daten oder ein erneutes Lesen persistierter Daten. An dieser Stelle habe ich dann eine entsprechende Anfrage an Oracle-L gestellt und mehrere hilfreiche Antworten bekommen. Den aus meiner Sicht entscheidenden Punkt hat dann wiederum Stefan Koehler beigesteuert: zwar behauptet die Dokumentation, dass die Daten persistiert werden, aber in Maria Colgans Whitepaper zum Verhalten des Optimizers in 12c liest man: "In order to minimize the performance impact, the results of the dynamic sampling queries will be persisted in the cache, as dynamic statistics, allowing other SQL statements to share these statistics." Persistierung im Cache ist nicht unbedingt das, was ich unter Persistierung verstehe, aber zumindest erklärt der Satz das Verhalten. Stefan Koehler wies weiterhin darauf hin, dass die Statistikerfassung unter Umständen durch eine Plan Direktive festgeschrieben werden kann, aber das macht den gesamten Vorgang aus meiner Sicht nicht weniger undurchsichtig: offenbar kann es in 12c sehr schwierig werden, die Kalkulationen des Optimizers nachzuvollziehen, weil man keinen direkten Zugriff auf seine Entscheidungsgrundlage hat. Wichtige statistische Informationen werden ad-hoc beschafft, temporär vorgehalten und unter Umständen später wieder neu beschafft - was dann unter Umständen Änderungen der (gesampelten) Basisdaten mit sich bringen kann. Da die Statistikerfassung von der Ausführung komplett getrennt sein kann, ist es über das Dictionary nicht möglich, die notwendigen Informationen zusammenzustellen - und selbst ein SQL-Trace kann die Angaben verpassen (wenn sie bereits zu einem früheren Zeitpunkt in den Cache gebracht wurden). Dass dynamic sampling ein großartiges Hilfsmittel sein kann, steht dabei für mich außer Frage - aber eine weniger intransparente Behandlung der Ergebnisse würde mir besser gefallen.

Mittwoch, Dezember 10, 2014

Analyse von Parsing-Effekten mit ASH

In seinem jüngsten Artikel stellt Jonathan Lewis einen ziemlich extremen Fall von Parsing in einem System mit zahlreichen sehr ähnlichen - und recht komplexen - Queries vor. Eine Query, die im Testsystem in 7 Sekunden optimiert werden kann, benötigt im Produktivsystem 415 Sekunden für das Parsen. Dafür verantwortlich ist offenbar die Tatsache, dass der Server unter extremer Last steht und mehr CPU verwenden will als verfügbar, und dass zahlreiche sehr ähnliche Queries gleichzeitig optimiert werden sollen, was eine massive Auseinandersetzung um die knappen Ressourcen (CPU, Latches, Mutexes) hervorruft. Die Analyse hat dabei einen vorläufigen Charakter, weil die vermutete (und plausible) Lösung der Verwendung von Bindewerten für die ähnlichen Queries zur Vermeidung der konkurrierenden Parse-Operationen noch nicht umgesetzt ist - sie würde während der inhaltlich erforderlichen 7 Sekunden zum Parsen der komplexen Query in anderen Sessions Waits des Typs "cursor: pin S wait on X" hervorrufen, die sich bekanntlich ergeben, wenn eine Session einen Plan benötigt, der gerade von einer anderen Session erzeugt wird.

Im Rahmen der Analyse erscheinen noch die folgenden erinnerungswürdigen Hinweise:
  • eine Analyse-Query auf Basis von v$active_session_history (sprich ASH), die die I/O und CPU Events zu einer sql_id (und sql_exec_id) aufführt und zusätzlich die Laufzeit des Parsens anzeigt (Attribute: in_parse, in_hard_parse)
  • die in ASH aufgeführten CPU-Angaben entsprechen nicht exakt den Angaben in v$sql, was der Autor auf die hohe Last im System zurückführt: "when we compare v$sql with ASH the difference in CPU is (statistically speaking) time spent in the run queue. So of our 447 seconds of CPU recorded by ASH, we spent 161 seconds in the CPU run queue waiting for CPU." In ASH ist demnach in entsprechenden Fällen mit größeren CPU-Laufzeitangaben zu rechnen.
Das Ergebnis ist - wie gesagt - anscheinend noch ein vorläufiges. Ich gehe aber davon aus, dass Jonathan Lewis - wie üblich - die abschließende Pointe noch nachliefern wird.

Dienstag, Dezember 09, 2014

PowerQuery mit SSAS

Viel habe ich nicht mehr zu SSAS zu sagen, aber der Hinweis von Chris Webb, dass PowerQuery in der aktuellen Version jetzt auch SSAS Multidimensional und Tabular Quellen als Datenbasis verwenden kann, sollte nicht unerwähnt bleiben. Dabei wird intern MDX erzeugt - "while it’s a bit strange in places it’s basically good and should perform well."