Freitag, August 29, 2014

String-Aggregation im SQL Server

Eine Funktionalität, die in Oracle und postgres schon seit längerer Zeit verfügbar ist, aber im SQL Server noch auf der (connect) Wunschliste steht, ist die String-Aggregation - also die Möglichkeit einer Gruppierung, bei der mehrere Elemente einer Gruppe in einem Feld konkateniert werden (also z.B. alle Mitarbeiter eines Departments in Oracles klassischer EMP-Tabelle). Für den SQL Server gibt es immerhin diverse Möglichkeiten, das Verhalten nachzubilden, und Aaron Bertrand stellt diese Varianten und ihr Verhalten (und insbesondere ihre Performance) im SQLPerformance.com Blog vor. Interessant finde ich unter anderem, dass die (für mich) nahe liegende Variante der Verwendung einer rekursiven CTE im Test mit großem Abstand die langsamste Lösung darstellt. 

Donnerstag, August 28, 2014

Commit-Korrekturen mit git

Hat nichts mit Datenbanken zu tun, sondern mit Versionsverwaltung: git benutze ich zwar schon seit einiger Zeit, habe es aber trotz ernsthafter Absichten nie geschafft, mir die Details ausreichend genau anzuschauen, um auf unerwartete Probleme angemessen reagieren zu können. Daher hat mir der Hinweis eines Kollegen auf den Artikel On undoing, fixing, or removing commits in git von Seth Robertson sehr geholfen, denn darin steht, was zu tun ist, wenn man sich in eine unglückliche Lage manövriert hat.

Nachtrag 03.11.2014: und hier noch ein paar Hinweise zur Verschönerung für git log von Filipe Kiss.

Montag, August 25, 2014

Neue Features in Postgres

Eine kleine Sammlung neuer Features, die in Postgres 9.4 eingeführt wurden bzw. in 9.5 eingeführt werden sollen - oder darin wünschenswert wären:
  • Craig Kerstiens hat dieser Tage seine Wunschliste mit neuen Features, die er gerne in Version 9.5 sehen würde, veröffentlicht. Auf Position 1 steht dabei das Upsert - aka MERGE - und das scheint auch mir die erstaunlichste Lücke im gegenwärtigen postgres-Funktionsumfang zu sein. Immerhin ist es seit Version 9.1 möglich, MERGE mit Hilfe von CTEs nachzubilden - allerdings scheint das Verfahren ein paar potentielle Probleme (race conditions, lost updates) hervorzurufen.
  • Über ein in 9.5 definitiv umgesetztes Feature schreibt Michael Paquier: die Möglichkeit, das WAL-Logging für eine Tabelle via ALTER TABLE zu aktivieren und zu deaktivieren. Grundsätzlich gibt es unlogged tables bereits seit Version 9.1, aber eine Umstellung des Verhaltens war bislang nicht möglich. Etwas ausführlicher ist der Artikel, den Hubert Lubaczewski zum gleichen Thema geschrieben hat.
  • Josh Berkus erläutert die bereits mit 9.4 eingeführte Funktion percentile_cont, deren Verhalten anscheinend dem der gleichnamigen Funktion unter Oracle entspricht.

Freitag, August 22, 2014

Abgeleitete IS NOT NULL Prädikate

Jonathan Lewis weist (im Rahmen einer Quiz-Frage, die sehr schnell ihre Antwort fand) darauf hin, dass der Optimizer implizite IS NOT NULL Prädikate schon seit vielen Releases aus der Join-Bedingung ableiten kann (im Sinne von: wenn ein Join durchgeführt wird, kann die Join-Bedingung keine NULL-Werte enthalten haben).

Mittwoch, August 20, 2014

drop table people

Wenn es bei xkcd einen Strip mit SQL-Queries gibt, muss er hier verlinkt werden - auch wenn's vielleicht eher um ein philosophisches Problem geht.

Dienstag, August 12, 2014

Definition von AWR Intervallen

Doug Burns hat dieser Tage in seinem Blog zwei Artikel zum Thema der Definition von AWR Intervallen veröffentlicht. Erinnerungswürdig scheinen mir dabei vor allem die folgenden beiden Punkte:
  • in einem produktiven System ist es sinnvoll, die Retention der AWR Snapshots auf einen deutlich höheren Wert als den default von 8 Tagen zu setzen (35-42 Tage oder gleich: unbegrenzt). 
  • weniger sinnvoll ist es, die AWR Intervalle selbst zu verkürzen: also vom Standard-Intervall von 1h auf 15 oder 30 min zu gehen. Die Begründung dieser Empfehlung ist, dass es zum Zweck der detaillierten Analyse andere geeignetere Tools gibt (ASH, SQL Monitoring), während AWR eher zur globalen Analyse des Systemverhaltens gedacht ist, und in diesem Fall erschweren kleinere Intervalle die Auswertung.
Das halte ich für einleuchtend.

Freitag, August 08, 2014

APPROX_COUNT_DISTINCT

Eigentlich stand auf meinem Erledigungszettel die Idee, eine kurze Untersuchung der in 12.1.0.2 neu eingeführten APPROX_COUNT_DISTINCT Funktion durchzuführen, mit deren Hilfe man die ungefähre Anzahl der distinkter Werte in einer Spalte effizient ermitteln können soll - aber Luca Canali hat gerade einen entsprechenden Artikel veröffentlicht und so genau wie der Herr Canali hätte ich mir den Fall ohnehin nicht angeschaut. Hingewiesen wird im Artikel unter anderem auf folgende Punkte:
  • beim count(distinct column_value) hängt die Performance entscheidend von der Notwendigkeit großer Sortierungen ab - und damit von der Spaltenbreite und der Anzahl distinkter Werte: je breiter die Spalten und je näher die Anzahl unterschiedlicher Werte an die Satzanzahl heranreicht, desto teurer werden die Sortierungen (inklusive temp I/O waits).
  • APPROX_COUNT_DISTINCT basiert auf einem Verfahren, dass eine geringe Memory-Nutzung erfordert und das gut skaliert. Bezahlt wird diese Optimierung mit einem Verzicht auf vollständige Genauigkeit: wie der Name der Funktion schon andeutet, wird nicht gezählt, sondern überschlagen.
  • In den Tests des Herrn Canali ergibt sich eine massive Beschleunigung der Operationen bei einer recht hohen Genauigkeit. Dabei betrifft die Beschleunigung natürlich in erster Linie die Fälle, in denen das exakte Zählen kostspielig wird (also: viele distinkte Werte, breite Spalten) - für Spalten mit sehr niedriger Kardinalität nähert sich die Laufzeit beider Operationen der Zeit, die für das Lesen der Daten (über FTS oder IFFS) benötigt wird.
  • der APPROX_COUNT_DISTINCT-Aufruf lässt sich sehr gut parallelisieren.
  • hinter der neuen Funktion steht der HyperLogLog (HLL) Algorithmus, den Alex Fatkulin (in einem bei Luca Canali verlinkten Artikel) folgendermaßen erläutert: "in a nutshell, it relies on counting the number of trailing (or leading) zeroes in the binary stream and using that information to estimate number of unique values with a very high degree of accuracy."
  • im Flame Graph der Operation (ohne den zu ergänzen der Herr Canali dieser Tage keinen Artikel beendet) findet man den Aufruf von qesandvHllAdd.
  • nicht ganz klar ist mir, ob der verwendete Algorithmus mit dem des in der Statistikerzeugung verwendeten approximate NDV identisch ist - Christian Antognini scheint das zu verneinen.
Für geeignete Fragestellungen sollte die Funktion jedenfalls ziemlich nützlich sein.

Nachtrag 23.10.2014: Christian Antognini zeigt, dass die Genauigkeit der Funktion für numerische Werte recht gut ist (Abweichung höchstens 4%), bei deutlich reduzierter Ressourcennutzung und erhöhter Performance gegenüber der Standardfunktion.

Donnerstag, August 07, 2014

ALTER INDEX ... COMPUTE STATISTICS ist wirklich deprecated...

Im OTN-Forum wurde dieser Tage die Frage gestellt, ob nach einem Index-Aufbau ein expliziter Neuaufbau von Statistiken erforderlich ist. In einem Kommentar erwähnte ein Diskussionsteilnehmer sein Standardverfahren des Aufrufs von ALTER INDEX ... COMPUTE STATISTICS nach dem Index-Aufbau. Nun hatte ich eine relativ klare Vorstellung von den Unterschieden bei der Statistikerstellung unter Verwendung des (veralteten) ANALYZE-Kommandos (für Tabellen) und dem (aktuellen) Aufruf von DBMS_STATS.GATHER_TABLE - aber keine Ahnung, wie die Statistiken aussehen, die durch ALTER INDEX ... COMPUTE STATISTICS erzeugt werden. Ein Test zeigt ein recht drastisches Ergebnis: offenbar leistet die COMPUTE STATISTICS-Option des ALTER INDEX-Kommandos in 11.2 rein gar nichts:

-- 11.2.0.1
-- drop test table
drop table t;
 
-- create test table
create table t
as
select rownum id
    , mod(rownum, 10) col1
  from dual
connect by level <= 100000;
 
-- delete a lot of rows
create index t_idx on t(id);
delete from t where col1 <= 5;
commit;
 
-- statistics after object creation and delete
select index_name, num_rows, leaf_blocks, last_analyzed from user_indexes where index_name = 'T_IDX';
 
INDEX_NAME                      NUM_ROWS LEAF_BLOCKS LAST_ANALYZED
----------------------------- ---------- ----------- -------------------
T_IDX                             100000         222 04.08.2014 19:59:22
 
-- table stats deleted
exec dbms_stats.delete_table_stats(user, 't')
 
select index_name, num_rows, leaf_blocks, last_analyzed from user_indexes where index_name = 'T_IDX';
 
INDEX_NAME                      NUM_ROWS LEAF_BLOCKS LAST_ANALYZED
----------------------------- ---------- ----------- -------------------
T_IDX
 
-- alter index compute statistics;
alter index t_idx compute statistics;
 
select index_name, num_rows, leaf_blocks, last_analyzed from user_indexes where index_name = 'T_IDX';
 
INDEX_NAME                      NUM_ROWS LEAF_BLOCKS LAST_ANALYZED
----------------------------- ---------- ----------- -------------------
T_IDX
 
-- dbms_stats
exec dbms_stats.gather_table_stats(user, 't', cascade=>true)
 
select index_name, num_rows, leaf_blocks, last_analyzed from user_indexes where index_name = 'T_IDX';
 
INDEX_NAME                      NUM_ROWS LEAF_BLOCKS LAST_ANALYZED
----------------------------- ---------- ----------- -------------------
T_IDX                              40000         222 04.08.2014 19:59:24

Eine ganz so große Überraschung ist dieses Verhalten allerdings insofern nicht, als bereits die Dokumentation zu 10.2 erklärte:
COMPUTE STATISTICS Clause: This clause has been deprecated. Oracle Database now automatically collects statistics during index creation and rebuild. This clause is supported for backward compatibility and will not cause errors.
In der Dokumentation zu 11g erscheint die Klausel überhaupt nicht mehr.

Freitag, August 01, 2014

SQL Server ETL mit T-SQL oder SSIS

Es ist schon eine Weile her, dass ich ernsthaft mit dem SQL Server gearbeitet habe - und ich bin mir nicht sicher, ob ich ernsthaft behaupten würde, je ernsthaft mit den SQL Server Integration Services (SSIS) gearbeitet zu haben. An Projekten, in denen SSIS eingesetzt wurde, war ich allerdings beteiligt, habe aber immer dafür plädiert, die SSIS in diesem Zusammenhang nur als Container für SQL-Operationen zu verwenden - ganz im Sinne eines älteren Artikels von James Serra, der sich mit den Vorteilen von SSIS und T-SQL im ETL-Zusammenhang beschäftigt, und dort anmerkt:
If you decide T-SQL is the way to go and you just want to execute a bunch of T-SQL statements, it’s still a good idea to wrap them in SSIS Execute SQL Tasks because you can use logging, auditing and error handling that SSIS provides that T-SQL does not.  You can also easily run SSIS Execute SQL Tasks in parallel so you are able to run stored procedures in parallel.
Darüber hinaus liefert der Artikel eine ganze Reihe von Argumenten für und wider die beiden Varianten. Auf die Idee, den Artikel hier zu erwähnen, hat mich die aktuelle Notiz SQL Server Agent job steps vs SSIS gebracht, die neben einem Link auf den älteren Artikel auch noch ein paar zusätzliche Anmerkungen zum SQL Server Agent enthält - was der Titel vielleicht schon andeutet...