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)