2016-09-15 2 views
1

Wir versuchen, Änderungserkennung in out ETL-Prozess zu implementieren.Sql - Bulk-Crypto-Hash-Generierung

So haben wir beschlossen, den verschlüsselten Hash mit

SET a.[HASH] = (SELECT 
        master.dbo.fn_varbintohexsubstring(0, HashBytes('md5', (SELECT TOP 1 * FROM customer_demographics_staging b WHERE b.customer_no = a.customer_no FOR XML RAW)), 1, 0)) 
FROM customer_demographics_staging a 

Für eine Tabelle mit 700k Aufzeichnungen und etwa 140 Spalten zu bekommen (wir sind noch die wechselnden Spalten bestimmen), die Abfrage laufen für etwa eine halbe Stunde vor Wir haben es abgebrochen.

Gibt es trotzdem, abgesehen von der Verringerung der Anzahl der Abfragen können wir das verbessern?

Antwort

1

Ein paar Dinge. Wenn der Datentyp der Spalte HASHvarbinary(20) ist, müssen Sie sich nicht mit der Konvertierung des MD5-Hashwerts in eine Zeichenfolge befassen. Speichern Sie einfach die Hash-Bytes. Wenn Sie jedoch zu diesem Zweck einen kryptografischen Hash für die Änderungserkennung verwenden möchten, verwende ich eine Inline-Tabellenwertfunktion, um sie zu erhalten. Hier ist ein Beispiel, das ich zusammengeschustert mit Adventure:

ALTER TABLE [HumanResources].[Employee] ADD [Hash] VARBINARY(20) NULL; 
GO 
CREATE FUNCTION dbo.CalculateHash(@EmployeeID AS INT) 
RETURNS TABLE 
AS 
    RETURN 

    SELECT e.[BusinessEntityID], HASHBYTES('md5', (
     SELECT * 
     FROM [HumanResources].[Employee] AS [e2] 
     WHERE [e2].[BusinessEntityID] = e.[BusinessEntityID] 
     FOR XML RAW 
    )) AS [Hash] 
    FROM [HumanResources].[Employee] AS [e] 
    WHERE [e].[BusinessEntityID] = @EmployeeID 

go 
SELECT TOP 10 [e].*, ch.[Hash] 
FROM [HumanResources].[Employee] AS [e] 
CROSS APPLY dbo.[CalculateHash]([e].[BusinessEntityID]) AS [ch] 
GO 

Das heißt, wenn es nach mir ginge, würde ich nicht mit MD5 überhaupt die Mühe und nur verwenden, um die CHECKSUM() Funktion (vielleicht als eine persistente berechnete Spalte in der Tabelle). Es unterstützt die native Übernahme mehrerer Spalten (sodass Sie nicht den Overhead für die Serialisierung der Zeile in XML aufwenden müssen).

+0

Das sieht wirklich gut aus. Ich werde es versuchen und Sie wissen lassen. Bezüglich der Verwendung von CHECKSUM wurde in der Dokumentation erwähnt, dass sie sich nicht ändern kann, wenn sich Werte ändern, und daher nicht ideal für die Erkennung von Änderungen ist. Es war unsere erste Wahl. – frostymarvelous

+0

Ich denke, das ist nur ein CYA insofern, als * irgendein * Hashing-Algorithmus Kollisionen haben wird (MD5 enthalten). Sie können der Tabelle auch eine Spalte mit der Zeile "rowversion" hinzufügen und die Berechnung vollständig überspringen. –

+0

Rowversion wird nicht funktionieren, da wir die Daten aus einer Oracle-Datenbank mit SSIS extrahieren. – frostymarvelous

1

Im Einklang mit dem, was [Ben Thul] bereits sagte, tendiere ich auch einfach auf BINARY_CHECKSUM(), weil es einfach zu bedienen ist. Ich stimme zu, dass diese Funktion "but ein int" zurückgibt, die 8 Bytes ist, während zB MD5 eine varbinary (16) zurückgibt, die doppelt so viel von Bytes ist, so erhalten Sie das Quadrat (nicht die doppelte!) Von 'result- Raum "bedeutet, dass Sie bei Kollisionen eine unglaublich viel geringere Chance haben. Aber paranoid möchte ich hinzufügen, dass eine genaue Übereinstimmung der MD5-Werte nicht bedeutet, dass Sie auch die gleichen (Eingabe-) Werte haben!

In aller Ehrlichkeit, benutze ich die Funktion nur, um Unterschiede zu beseitigen. Wenn das Ergebnis der Prüfsumme (oder des Hash) unterschiedlich ist, können Sie 100% sicher sein, dass die Werte auch unterschiedlich sind. Wenn sie identisch sind, sollten Sie die Quellwerte in ihrer Gesamtheit überprüfen, um zu sehen, ob es keine "falschen Übereinstimmungen" gibt.

Ihr Anwendungsfall scheint genau andersherum zu sein: Sie möchten diejenigen finden, die anders sind, indem Sie die identischen eliminieren, und die Letzteren ausschließen, indem Sie nur den Hash-Code betrachten. Um ehrlich zu sein, bin ich kein Fan des Ansatzes, nur weil Sie Gefahr laufen, in eine Kollision zu geraten, die einen 'geänderten' Datensatz in Ihrer Staging-Tabelle verursacht, um genau denselben Hash-Wert wie der alte zu erhalten und somit ignoriert zu werden Kopieren Sie die Änderungen. Auch hier sind die Chancen unglaublich klein, aber wie ich schon sagte, ich bin paranoid, wenn es dazu kommt =)

Wenn Sie diesen Track dennoch einige Bemerkungen, weiter zu gehen würde mir wünschen:

  • HashBytes unterstützt nur eine Eingabe von 8000 Bytes. In Anbetracht der Overhead durch die XML-Syntax hinzugefügt Sie in Schwierigkeiten mit den 140 Spalten laufen könnte
  • Ich habe keine (gut) Grund sehen das Ergebnis HashBytes, um etwas anderes zu konvertieren, bevor es auf den Tisch
  • Obwohl FOR XML Schreiben ist ziemlich schnell, würde nicht CONCAT genauso schnell sein, während gleichzeitig ein "kleineres" Ergebnis resultiert (vgl. Punkt 1)?Ich stimme zu, dass es eine Reihe von Problemen mit sich bringt, etwa wenn field1, field2, field3 "hallo", "world" "" dasselbe bedeutet wie "hallo", "", "world" =/You könnte umgehen diese von CONCAT -ing die LEN() von jedem Feld zu ... nicht sicher, wie viel Gewinn wir aber übrig hätten =)
  • Ich vermute, Sie haben es bereits, aber gibt es einen Index, vorzugsweise einzigartig und gruppiert, auf dem Feld in der Staging-Tabelle?
+0

Danke für sehr gültige Punkte angesprochen. Wir haben uns tatsächlich dafür entschieden, mit concat zu arbeiten und die Anzahl der Spalten, die wir verfolgen möchten, zu begrenzen (wir stellen auch sicher, dass wir die Reihenfolge jedes Mal einhalten). Anstatt den LEN zu verwenden, begrenzen wir jede Spalte. Wir werden die Konvertierung in varchar zugunsten der rohen Bytes löschen, da sie mehr als einmal ausgelöst wurde. – frostymarvelous