Alexander Förster

In einem aktuellen Projekt galt es, große Datenmengen zu laden, durch die es theoretisch in der gesamten Tabelle zu Änderungen kommen konnte. Eine tägliche Komplettbewirtschaftung der Faktentabelle war aufgrund der Masse an Daten ausgeschlossen. Ebenso wenig war eine Abgrenzung über ein Datum – wie zum Beispiel „das letzte halbe Jahr neu laden“ – möglich. Infolgedessen konnte die übliche Deltabewirtschaftung nicht vorgenommen werden. Die Lösung hat indes ein Timestamp in der Quelltabelle gebracht.

Vorteile und Nachteile bei der Deltabewirtschaftung

Bei einem Timestamp handelt es sich nicht um einen echten Zeitstempel, sondern eher um ein Row- bzw. Zeilenversion. In der MSDN werden diese auch gleich gesetzt. Der Datentyp „Timestamp“ oder „Rowversion“ ist zwar laut Microsoft abgekündigt, allerdings wird dies erfahrungsgemäß nicht allzu bald erfolgen. Intern wird der Timestamp als „binary(8)“ bzw. „varbinary(8)“ gespeichert.

Ein Vorteil des Timestamps ist, dass bei jeder Änderung die betreffende Spalte automatisch aktualisiert wird und eindeutig ist. Dadurch lassen sich Änderungen für eine Deltabewirtschaftung sehr leicht umsetzen. Als Nachteil erweist sich bei dieser Form der Deltabewirtschaftung die Verwendung im SSIS. Hier wird der Datentyp ohne Konvertierungen als „DB_Bytes“ interpretiert. Diesen kann man denkbar schlecht vergleichen. Bei der Verwendung in Queries muss der Datentyp in einen String (varchar) konvertiert und ohne „`“ verwendet werden. Darüber hinaus macht es meist keinen Sinn, in den Quelltabellen nach einer solchen Spalte zu sortieren oder gar zu partitionieren, wie es üblicherweise bei monatsweise getrennten Daten der Fall ist.

Daten selektieren, Mehrfachbeladung vermeiden

Der folgende Ansatz beschreibt, wie sich die Daten dennoch selektieren und Mehrfach- oder Doppelbeladung einzelner Datensätze bei etwaigen Abbrüchen vermeiden lassen. In einem ersten Schritt haben wir in unserem Paket einen SQL-Script-Task eingebaut, der uns den letzten geladenen Timestamp aus einer Steuerungstabelle holt:

Deltabewirtschaftung mit Timestamp: SQL-Task-Script für den letzten geladenen Timestamp.

 

Um hier immer einen gültigen Wert zu haben, wird mit dem kleinstmöglichen Timestamp vereint:

SELECT TOP 1  deltavalue FROM (
SELECT [deltavalue]
FROM   [Control].[tabledeltavalues]
WHERE  [tablename] = ‚[dbo].[MeineDeltaTabelle]‘
UNION
SELECT ‚0x0000000000000001‘)b ORDER BY 1 DESC

 

Im zweiten Schritt löscht man in der Zieltabelle alle Werte, die größer als der zuletzt gespeicherten Timestamp sind:

Löschen aller Werte, die größer als der zuletzt gespeicherte Timestamp sind.

Auf diese Weise wird eine Mehrfachbeladung einzelner Datensätze vermieden. Wer häufig Abbrüche im Paket hat, der sollte sich im Übrigen Gedanken über die Kompressionmethode der Zieltabelle machen.

 

Bei der Selektion der Daten für die Beladung ist dann die entsprechende Where-Bedingung hinzuzufügen:
WHERE  zeitstempel > „mintimestamp“

 

Zuletzt muss nur noch der zuletzt gelesene Timestamp weggeschrieben werden:

blog2
MERGE [Control].[tabledeltavalues] AS target
using (SELECT ‚[dbo].[MeineDeltaTabelle]‘
AS
tablename,
CONVERT(NVARCHAR (50), Cast(Max (zeilenversion) AS VARBINARY(8)),1) AS Deltavalue
FROM   [dbo].[meinedeltatabelle]) AS Source
ON target.tablename = source.tablename
WHEN matched THEN
UPDATE SET target.deltavalue = source.deltavalue
WHEN NOT matched BY target THEN
INSERT (tablename,
deltavalue )
VALUES (‚[dbo].[MeineDeltaTabelle]‘,
           source.deltavalue );