Sonntag, September 28, 2014

Analyse des Oracle Kernel Verhaltens mit SystemTab

Luca Canali beschäftigt sich in seinem Blog recht regelmäßig mit Hilfsmitteln, die es erlauben, das Verhalten des Oracle Servers im Zusammenspiel mit den OS-Komponenten zu untersuchen. Ein solches Hilfsmittel ist das tracing and probing tool SystemTab, das die Arbeitsweise des Linux-Kernels ausleuchtet. Im Artikel zeigt der Autor die Möglichkeiten der Verknüpfung von SystemTab mit dem Oracle Wait Interface und den X$-Strukturen:
These techniques aim to be useful as well as fun to learn for those keen into peeking under the hood of the technology and improve their effectiveness in troubleshooting and performance investigations.
Die Details nachzuerzählen, erspare ich mir und belasse es bei diesem Verweis, dem ich möglicherweise gelegentlich intensiver nachgehen könnte.

Montag, September 22, 2014

Attribut-Clustering mit 12.1.0.2

Richard Foote hat schon vor einigen Wochen eine kurze Einführung zum Feature Attribute Clustering geliefert, das in 12.1.0.2 verfügbar wurde. Dieses Feature ermöglicht die Angabe einer Clustering-Klausel im CREATE TABLE-Kommando, die eine (ungefähre) physikalische Clusterung der Tabellendaten nach dem Inhalt einer angegebenen Spalte (oder auch mehrerer Spalten) hervorruft. Eine Syntax-Variante dazu lautet etwa:
create table ...
clustering by linear order (col1)
Diese Klausel ruft beim Direct-Path Insert neuer Daten eine Sortierung hervor, die sicherstellt, dass die Daten am geeigneten Platz eingefügt werden - was natürlich einen Einfluss auf die Performance der Operation hat. Umgekehrt ist dafür dann der Clustering-Factor entsprechend sortierter Indizes niedriger, was sich dann wieder positiv auf entsprechende Index-Zugriffe auswirkt. Für conventional path DML wird das Feature nicht unterstützt (worauf Stefan Köhler in seinem Kommentar hinweist). Demnach scheinen hier OLTP-Systeme wohl nicht das vorgestellte Ziel zu sein.

Donnerstag, September 18, 2014

Buffer re-visits im Rahmen von Index Range Scans

Nichts Neues, aber ein schönes Beispiel für eines der zentralen Themen bei der Optimierung von Zugriffen in relationalen Datenbanken: Tanel Poder erläutert in seinem Artikel About index range scans, disk re-reads and how your new car can go 600 miles per hour!, warum die Ergänzung von Indizes für analytische Queries (mit Zugriff auf größere Datenmengen) in vielen Fällen keine besonders gute Idee ist: der Zugriff über den (sortierten) Index führt zum wiederholten Zugriff auf die (unsortierten) Tabellendaten - der gleiche data block wird unter Umständen wieder und wieder besucht, so dass das Volumen der gelesenen Daten letztlich das Volumen der Tabelle (und des Index) massiv übersteigt. Diese re-visit-Effekte werden sichtbar in den Trace-Files, die mit Hilfe der Events 10046 (also SQL Trace) und 10298 (ksfd i/o tracing) erzuegt wurden - letzteres enthält die blkno (also Blocknummer), die im Beispiel in einigen Fällen zehn Mal erscheint. Da diese erneuten Besuche (nach Buffer Cache Maßstäben) zeitlich weit auseinander liegen können, ergeben sich für viele re-visits physikalische Leseoperationen, weil die Daten durch folgende reads bereits wieder aus dem Cache verdrängt wurden. Mit Hilfe von (range scans auf) Indizes sind Massendatenoperationen oft nicht optimierbar, was den Herrn Poder zum - ein klein wenig reißerisch klingenden - Titel seines Artikels bringt: um dramatische Beschleunigungen für große Reporting-Fragestellungen zu erreichen, benötigt man andere Verfahren - und dabei denkt er an Exadata und die In-Memory-Option: also Strategien, die die relevanten Datenmengen reduzieren und dabei die Zugriffsstrategien grundsätzlich verändern.

Dienstag, September 16, 2014

Set to Join Konvertierung

Noch ein interessanter Hinweis von Franck Pachot auf eine Transformation, die der Optimizer bereits seit längerer Zeit beherrscht, die aber nur aktiv wird, wenn optimizer_feature_enabled auf 12.1.0.2.1 gesetzt wird - also auf eine Version, die es bisher noch gar nicht gibt. Per Hint (SET_TO_JOIN) kann man die Verwendung des Verfahrens aber bereits seit längerer Zeit aufrufen und erreicht damit, dass Set-Operationen wie MINUS oder INTERSECT in einen Join umgewandelt werden, was für geeignete Mengenverhältnisse durchaus interessant sein kann, insbesondere weil es potentiell kostspielige SORT UNIQUE Operationen vermeiden kann.

Freitag, September 12, 2014

COUNT_DISTINCT für postgres

Thomas Vondra erläutert in seinem Blog die selbst gebaute Funktion COUNT_DISTINCT, mit deren Hilfe sich COUNT(DISTINCT column) Operationen beschleunigen lassen, da sie auf eine (inhaltlich unnötige) Sortierung der Ergebnisse verzichtet. Ursprünglich verwendete er bei seiner Implementierung eine Hash Table, die inzwischen aber durch ein einfaches Array mit sortierten und unsortierten Elementen ersetzt wurde. Interessant finde ich dabei einerseits die großartigen Möglichkeiten der Erweiterbarkeit des postgres-Funktionsumfangs und andererseits die Tatsache, dass hier offenbar ein ähnlicher Lösungsweg gewählt wurde wie der, den Oracle (und andere) bei der Implementierung von HASH GROUP BY Operationen gewählt haben.

Vorteile des Zugriffs auf den In-Memory column store.

Maria Colgan erläutert im Rahmen ihrer Serie zur In-Memory-Option in Oracle 12.1.0.2 die spezifischen Vorteile, die ein TABLE ACCESS IN MEMORY FULL mit sich bringt:
  • der Zugriff beschränkt sich auf die relevanten Spalten - was bei der klassischen Zeilen-orientierten Speicherung natürlich nicht möglich wäre.
  • die IM-Daten liegen in komprimierter Form vor, weil sie beim Laden in den Speicher komprimiert werden.
  • unnötige Daten werden beim Lesen ausgeschlossen, was durch In-Memory Storage Indexes sichergestellt wird. Diese Indizes enthalten die minimalen und maximalen Werte, die in einer In-Memory Compression Unit (IMCU) gespeichert sind.
  • Optimierung des Zugriffs auf relevante IMCUs durch SIMD vector processing (Single Instruction processing Multiple Data values). Diese Strategie erlaubt (wie der Name andeutet) die gleichzeitige Verarbeitung mehrerer Spaltenwerte innerhalb einer einzigen CPU instruction.
Zur Analyse des Verhalten gibt es in v$statname allerhand neue IM scan % Statistiken, die man sich im Rahmen einer intensiveren Beschäftigung mit dem Thema genauer anschauen sollte.

Mittwoch, September 10, 2014

Tabellenzugriff über Index-Kombinationen

In seinem Blog hat Jonathan Lewis dieser Tage die Quizfrage gestellt, wieso es möglich ist, dass eine Query mit einer Einschränkung der Form:
where col1 between 1 and 3
durch eine Umwandlung der Bedingung in die folgende Form optimiert werden kann:
where col1 = 1 or col1 > 1 and col1 <= 3
Die Antwort lautet (natürlich): durch die Kombination mehrerer Zugriffsmöglichkeiten - im Beispiel, an das der Herr Lewis gedacht hatte, geht es um die Kombination von bitmap Indizes, aber theoretisch wäre auch eine Kombination von B*Tree-Indizes möglich.

Montag, September 08, 2014

Pipelined Functions mit postgres

In Oracle dienen pipelined table functions dazu, PL/SQL collections als Tabellen zu verkleiden und darauf mit einfachem SQL zugreifen zu können. Hier ein kleines Beispiel dazu, wie man in postgres ein ähnliches Verhalten erreichen kann:

create or replace function f_pipeline_test(lines_limit int)
returns table (
    table_schema    text
  , table_name      text
) as
$func$

declare sqltext text = 'select table_schema::text, table_name::text
                          from information_schema.tables
                         where table_schema = ''pg_catalog''
                         limit ' || lines_limit;

begin

   return query
   execute sqltext;

end
$func$  language plpgsql;

select * from f_pipeline_test(5);

table_schema |  table_name
-------------+--------------
pg_catalog   | pg_statistic
pg_catalog   | pg_type
pg_catalog   | pg_roles
pg_catalog   | pg_shadow
pg_catalog   | pg_authid
(5 Zeilen)

Samstag, September 06, 2014

Unkokumentierter Result_Cache-Hint-Parameter in 12.1.0.2

Christian Antognini weist in seinem Blog darauf hin, dass der Hint result_cache in 12.1.0.2 einen Parameter erhalten hat, mit dessen Hilfe man festlegen kann, nach wie vielen Sekunden ein Ergebnis aus dem result cache gelöscht werden soll, auch wenn sich das zugrunde liegende Objekt nicht geändert hat. Dieser Parameter SNAPSHOT wird in der offiziellen Dokumentation nicht erwähnt.

Mittwoch, September 03, 2014

Jonathan Lewis über In-Memory-Effekte

In den letzten Wochen hat Jonathan Lewis einige Artikel zum Verhalten der in 12.1.0.2 erschienen In-Memory Option veröffentlicht, die ich hier kurz zusammenfasse - hauptsächlich allerdings, um die Links an geeigneter Stelle zu sammeln:
  • In-memory limitation: erläutert einen Fall, in dem die Kombination der In-Memory columnar storage mit der traditionellen Zeilen-basierten Ablage nicht das leistet, was man sich davon versprechen könnte - bzw. was sich der Herr Lewis hätte vorstellen können. Sein Beispiel enthält eine relativ breite Tabelle, deren Spalten zum Teil In-Memory abgelegt sind und zum Teil nicht. Ein Zugriff der sich auf die In-Memory Spalten beschränkt, wird auch über eine In-Memory-Operation abgebildet (im Plan: TABLE ACCESS INMEMORY FULL), aber so bald eine weitere "no inmemory" Spalte in der Select-Liste ergänzt wird, ergibt sich ein normaler FTS - obwohl es in diesem Fall unter Umständen effizienter wäre, die rowids der betroffenen Datensätze über den In-Memory-Zugriff zu bestimmen und darüber zuzugreifen. Anhand eines entsprechenden Beispiels mit allerlei Hints wird gezeigt, dass ein solcher Plan grundsätzlich möglich wäre, vom Optimizer aber nicht in Betracht gezogen wird. In einem Kommentar  von Franck Pachot und der Antwort von Jonathan Lewis gibt es noch ein paar Überlegungen zur Frage der technischen Umsetzung der rowid-Ablage im Rahmen der In-Memory Option, die allerdings an diser Stelle nicht definitiv beantwortet wird.
  • In-memory Aggregation: erklärt eine recht komplexe Variante der Optimierung von Aggregationen: "it’s a cunning mechanism combining aspects of the star-transformation (but without the bitmap indexes), Bloom filters, and “group-by” placement to minimise the cost of aggregation over high-volume joins." Angesichts der relativ hohen Komplexität des Verfahrens spare ich mir die Nacherzählung und beschränke mich auf die Erwähnung des Stichworts vector transformation (samt zugehörigem Hint; im Plan erscheinen dazu diverse Schritte zum Aufbau und zur Verwendung der Key Vector-Elemente, die - so weit ich es verstehe - In-Memory Key-Value-Elemente darstellen und deren Verwendung Ähnlichkeiten mit der von Bloom-Filtern besitzt).
  • In-memory Consistency: beschäftigt sich mit der Umsetzung von Lesekonsistenz im Rahmen der In-Memory Option und betrachtet dazu die Session-Statistiken. Die Ausführungen enthalten diverse Hinweise auf die relevanten Statistiken, aber, so weit ich sehe, keine extremen Überraschungen. 
Sollte Jonathan Lewis zeitnah weitere Artikel zum Thema liefern, so werde ich sie hier voraussichtlich ergänzen.