Zur Zeit wird gefiltert nach: t-sql
Filter zurücksetzen
SQL Server 2008 - Hash mit Checksum oder HashBytes?
In einer Vorphase für ein Projekt will ich prüfen, mit welchen Hashmechanismen eine vernünftige Änderungserkennung durchgeführt werden kann, ohne dass Kollisionen auftreten.
Liest man in der Dokumentation, so wird bei Checksum vor Kollisionen gewarnt, auch wenn diese Methode mit den Hashindizies sehr gute Dienste leisten kann. Stattdessen wird für Vergleiche auf HashBytes verwiesen.
Was ist nun der Vorteil, wenn die Änderungen mithilfe eines Hashwerts geprüft werden? Ein wesentlicher Aspekt ist natürlich die Performance, wenn ich nur eine Spalte abfragen muss, anstatt mehrere, die evtl. noch mit einer Nullprüfung, kratzt das schnell Mal an den Ressourcen.
Ein subjektiver Aspekt ist auch die verbesserte Lesbarkeit des SQL-Statements, welches abgesetzt wird. Hier ein kleines Beispiel:
Prüfen auf Änderungen jeder einzelnen Column (SQL)
SELECT
* -- Stern nicht in produktiven Umgebungen verwenden
FROM dbo.tbHashCollisionStageTest stage
WHERE EXISTS
(
SELECT 1
FROM tbHashCollisionTest fact
WHERE fact.OdsKey = stage.OdsKey
AND (fact.Customer <> stage.Customer
OR fact.Qty <> stage.Qty
OR fact.Price <> stage.Price
OR fact.Brand <> stage.Brand
OR fact.[Group] <> stage.[Group])
)
Prüfen auf Änderungen mit Hashwert (SQL)
SELECT
* -- Stern nicht in produktiven Umgebungen verwenden
FROM dbo.tbHashCollisionStageTest stage
WHERE EXISTS
(
SELECT 1
FROM tbHashCollisionTest fact
WHERE fact.OdsKey = stage.OdsKey
AND fact.HashB <> stage.HashB
)
Aus meiner Sicht ist die Abfrage, die mit einer Hashcolumn arbeitet, wesentlich übersichtlicher und macht das Statement weniger Komplex (Keep it simple). Es vereinfacht zudem auch die Logik zur automatischen Generierung dieser Statements.
Personen, die in Oracle-Umgebungen mit Performanceoptimierungen beschäftigt sind, werden bei dieser Syntax jedoch die Hände über den Kopf zusammenschlagen, da Oracle in solchen Szenarien besser mit JOINS/LEFT JOINS umgehen kann, anstatt mit EXISTS/NOT EXISTS. Es geht sogar so weit, dass es zum völligen Stillstand des Servers führen kann. Dieser Punkt ist auch für Hacker interessant, da bereits einfaches ANSI-SQL die Verfügbarkeit beeinträchtigen kann. ;-). Beim SQL-Server sind in der Regel solche Tricks nicht notwendig. Das ist jedoch eine andere Geschichte und die werde ich sicherlich in ein paar Beiträgen verarbeiten. *fg*
Kommen wir zurück zum Thema Kollisionen: Um nun feststellen zu können, wann es bei Checksum zu Problemen führt, habe ich eine Testtabelle mit ein paar wenigen Datensätzen gefüllt. In Zahlen ausgedrückt sind es 15 Mio. Datensätze. Mehr will ich meiner Schreibmaschine auch nicht antun, denn diese verfügt nicht über die soliden Grundlagen, die ein DWH-Server erfüllen sollte.
Mit der Abfrage auf die entsprechenden Spalten Hash (Checksum) HashB (HashBytes) kann nun auf eventuell auftretende Kollisionen geprüft werden. Wer dieses Szenario nachspielen will, muss jedoch darauf achten, dass eindeutige Testdaten erzeugt werden.
Das SQL-Statement für den Test hat folgende Syntax:
Test-Statement (SQL)
SELECT
COUNT(t.Hash) as Kollisionen
FROM
(
SELECT TOP X
Hash
FROM tbHashCollisionTest
) t
GROUP BY
t.Hash
HAVING COUNT(t.Hash) > 1
Das Ergebnis:
Anzahl Datensätze | Checksum | HashBytes (SHA1) |
|---|---|---|
1'000 | 0 Kollisionen | 0 Kollisionen |
10'000 | 0 Kollisionen | 0 Kollisionen |
100'000 | 3 Kollisionen | 0 Kollisionen |
1'000'000 | 104 Kollisionen | 0 Kollisionen |
5'000'000 | 2'937 Kollisionen | 0 Kollisionen |
10'000'000 | 11'624 Kollisionen | 0 Kollisionen |
15'000'000 | 26'269 Kollisionen | 0 Kollisionen |
Checksum verursacht bereits ab 100'000 Datensätzen Kollisionen, sodass diese für den geplanten Zweck nicht infrage kommen wird.
Social Bookmarking