it-swarm.com.de

Erkennen von Änderungen in einer SQL Server-Tabelle

In meiner Anwendung mit einer Datenbank, die unter SQL Server 2012 ausgeführt wird, habe ich einen Job (geplante Aufgabe), der regelmäßig eine teure Abfrage ausführt und die Ergebnisse in eine Tabelle schreibt, die später von der Anwendung abgefragt werden kann.

Im Idealfall möchte ich diese teure Abfrage nur ausführen, wenn sich seit der letzten Ausführung der Abfrage etwas geändert hat. Da die Quelltabellen sehr groß sind, kann ich nicht einfach eine Prüfsumme über alle Kandidatenspalten oder ähnliches auswählen.

Ich habe folgende Ideen:

  • Schreiben Sie explizit einen zuletzt geänderten Zeitstempel, ein Flag "Muss Abfragen sein" oder ähnliches in eine Tracking-Tabelle, wenn ich etwas in einer Quelltabelle ändere.
  • Verwenden Sie einen Auslöser, um dasselbe zu tun.

Ich würde jedoch gerne wissen, ob es eine einfache Möglichkeit gibt, Änderungen an einer Tabelle zu erkennen, ohne dass ich die Schreibvorgänge explizit verfolge. Kann ich zum Beispiel das "aktuelle" ROWVERSION einer Tabelle oder ähnliches abrufen?

13
Fabian Schmied

Nein, es gibt keine. Jede Art von "zuletzt aktualisiert um" -Verfolgung würde zu einem schwerwiegenden Leistungsproblem führen, da alle Aktualisierungen aus allen Transaktionen versuchen würden, den einen Datensatz zu aktualisieren, der die "zuletzt aktualisiert um" verfolgt. Dies würde effektiv bedeuten, dass zu jedem Zeitpunkt nur eine Transaktion die Tabelle aktualisieren kann und alle anderen Transaktionen auf die erste warten müssen, um festzuschreiben . Vollständige Serialisierung. Die Anzahl der Administratoren/Entwickler, die bereit sind, solche Leistungseinbußen in Kauf zu nehmen, nur um zu wissen, wann das letzte Update stattgefunden hat, ist wahrscheinlich gering.

Sie sind also gestrandet, um über benutzerdefinierten Code damit umzugehen. Dies bedeutet Trigger, da die Alternative (Erkennung aus Protokolldatensätzen) ein Vorrecht ist, das nur für die Transaktionsreplikation reserviert ist (oder CDC alter-ego). Beachten Sie, dass Sie genau das oben erwähnte Serialisierungsproblem haben, wenn Sie versuchen, es über eine Spalte "Zuletzt aktualisiert um" zu verfolgen. Wenn die Parallelität von Updates wichtig ist, müssen Sie einen Warteschlangenmechanismus verwenden (der Trigger verwendet ein INSERT und dann aggregiert ein Prozess die eingefügten Werte, um die 'letzte Aktualisierung um' zu formulieren). Versuchen Sie nicht, mit einer 'cleveren' Lösung zu schummeln, wie sich an die aktuelle Identität zu schleichen oder nachzuschlagen sys.dm_db_index_usage_stats . Und auch eine Spalte 'update_at' pro Datensatz, wie Rails Zeitstempel haben, funktioniert nicht, weil sie keine Löschvorgänge erkennt ...

Gibt es eine "leichte" Alternative? Eigentlich gibt es eine, aber es ist schwierig zu sagen, ob sie für Sie funktioniert, und es ist schwierig, sie richtig zu machen: Abfragebenachrichtigungen . Die Abfragebenachrichtigung führt genau das aus. Sie richtet eine Benachrichtigung ein, wenn Daten geändert wurden und Sie Ihre Abfrage aktualisieren müssen. Obwohl die meisten Entwickler nur mit der .Net-Inkarnation als SqlDependency vertraut sind, kann die Abfragebenachrichtigung als langlebiger, dauerhafter Mechanismus zum Erkennen von Datenänderungen verwendet werden. Verglichen mit der tatsächlichen Änderungsverfolgung wird es sehr leicht und seine Semantik entspricht eher Ihren Anforderungen (etwas, alles , was geändert wurde, also müssen Sie es tun Führen Sie die Abfrage erneut aus.

Aber am Ende würde ich an Ihrer Stelle meine Annahmen wirklich überdenken und zum Zeichenbrett zurückkehren. Möglicherweise können Sie den Protokollversand oder die Replikation verwenden, um eine Berichtsdatenbank auf einem anderen Server einzurichten. Was ich zwischen den Zeilen gelesen habe, ist, dass Sie eine ordnungsgemäße ETL-Pipeline und ein Analytics Data Warehouse benötigen ...

14
Remus Rusanu

Es sieht so aus, als wäre ich zwei Jahre zu spät zum Spiel, aber es gibt in der Tat eine ziemlich leichte Möglichkeit, das zu tun, wonach Sie fragen.

Es gibt zwei SQL Server-Mechanismen, die Ihnen helfen können. Ihre ultimative Lösung könnte eine Mischung aus beiden sein.

Änderungsverfolgung . SQL Server kann bestimmte Tabellen überwachen und nur aufzeichnen, welche Zeilen sich geändert haben (anhand ihres Primärschlüsselwerts) und welche Art von Änderung es war (Einfügen, Aktualisieren oder Löschen). Sobald Sie die Änderungserkennung für eine Reihe von Tabellen eingerichtet haben, können Sie anhand einer einfachen Abfrage feststellen, ob seit der letzten Überprüfung Änderungen an der Tabelle vorgenommen wurden. Der Overhead entspricht in etwa der Verwaltung eines zusätzlichen einfachen Index.

Zeilenversion/Zeitstempel. Dies ist ein varbinärer 8-Byte-Spaltentyp (der in ein BigInt umgewandelt werden kann), der datenbankweit inkrementiert wird, wenn eine Zeile, die eine enthält, eingefügt oder aktualisiert wird (dies hilft nicht beim Löschen). Wenn Sie diese Spalten indiziert haben, können Sie leicht feststellen, ob sich die Zeilendaten geändert haben, indem Sie den MAX (Zeitstempel) mit seinem Wert seit der letzten Auswertung vergleichen. Da der Wert monoton ansteigt, erhalten Sie einen zuverlässigen Hinweis darauf, dass sich die Daten geändert haben, wenn der neue Wert größer ist als beim letzten Überprüfen.

8
Curt

Wenn die Quelle nur einfügen ist, geben Sie ihr eine IDENTITY -Spalte. Wenn Sie Ihre Datenübertragung durchführen, protokollieren Sie den höchsten Wert, über den geschrieben wurde. Bei der nächsten Übertragung müssen Sie nur nach Werten fragen, die größer sind als die bei der vorherigen Übertragung protokollierten. Wir tun dies, um Protokollsätze in ein Data Warehouse zu übertragen.

Fügen Sie für aktualisierbare Zeilen ein "schmutziges" Flag hinzu. Es hat drei Werte - sauber, schmutzig und gelöscht. Bei täglichen Abfragen müssen Zeilen mit dem Flag "gelöscht" weggelassen werden. Dies ist in Bezug auf Wartung, Test und Laufzeit teuer. Nach der großen Abfrage, die Sie erwähnen, müssen alle zum Löschen markierten Zeilen entfernt und das Flag für alle anderen zurückgesetzt werden. Dies wird nicht gut skaliert.

Eine leichtere Alternative zu Change Data Capture ist Change Tracking . Es wird Ihnen nicht mitgeteilt, welche Werte sich geändert haben, nur dass sich die Zeile seit ihrer letzten Abfrage geändert hat. Integrierte Funktionen erleichtern das Abrufen geänderter Werte und die Verwaltung der Nachverfolgung. Es ist uns gelungen, mit CT etwa 100.000 Änderungen pro Tag in einer 100.000.000-Zeilentabelle zu verarbeiten.

Abfragebenachrichtigungen wirken immer noch auf einen höheren Hebel - auf der Ebene einer Ergebnismenge. Konzeptionell ist es wie das Definieren einer Ansicht. Wenn SQL Server feststellt, dass sich eine über diese Ansicht zurückgegebene Zeile geändert hat, wird eine Nachricht an die Anwendung gesendet. Es gibt keinen Hinweis darauf, wie viele Zeilen geändert wurden oder welche Spalten. Es gibt nur einfache Nachrichten mit der Aufschrift "Etwas ist passiert". Es liegt an der Anwendung, nachzufragen und zu reagieren. Praktisch ist es viel komplexer als das, wie Sie sich vorstellen können. Es gibt Einschränkungen, wie die Abfrage definiert werden kann, und die Benachrichtigung kann für andere Bedingungen als geänderte Daten ausgelöst werden. Wenn die Benachrichtigung ausgelöst wird, wird sie entfernt. Wenn später weitere interessante Aktivitäten stattfinden, wird keine weitere Nachricht gesendet. Es ist Sache des Anwendungsdesigners, sicherzustellen, dass die Aktivität zwischen einer Benachrichtigung und der anschließenden Wiederherstellung der Abfrage ordnungsgemäß verarbeitet wird.

Im Zusammenhang mit der Frage des OP hat QN den Vorteil eines geringen Einrichtungsaufwands und geringer Laufzeitkosten. Es kann ein erheblicher Aufwand sein, ein strenges System für die Reaktion auf Abonnementnachrichten einzurichten und aufrechtzuerhalten. Da die Datentabelle groß ist, werden sie wahrscheinlich häufig geändert, was bedeutet, dass die Benachrichtigung in den meisten Verarbeitungszyklen ausgelöst wird. Da es keinen Hinweis darauf gibt, welche geänderte inkrementelle Verarbeitung der Deltas nicht möglich ist, wie dies bei CT oder CDC der Fall wäre. Der Overhead aufgrund falscher Auslösung ist lästig, aber selbst im schlimmsten Fall muss die teure Abfrage nicht häufiger ausgeführt werden als derzeit.

7
Michael Green

SqlTableDependency

SqlTableDependency ist eine Implementierungskomponente auf hoher Ebene für den Zugriff auf Benachrichtigungen, die Tabellendatensatzwerte in der SQL Server-Datenbank enthalten.

SqlTableDependency ist eine generische C # -Komponente, die zum Empfangen von Benachrichtigungen verwendet wird, wenn sich der Inhalt einer angegebenen Datenbanktabelle ändert.

Was ist der Unterschied zu .NET SqlDepenency?

Grundsätzlich besteht der Hauptunterschied darin, dass SqlTableDependency Ereignisse sendet, die Werte für den eingefügten, geänderten oder gelöschten Datensatz sowie die in der Tabelle ausgeführte DML-Operation (Einfügen/Löschen/Aktualisieren) enthalten: SqlDepenency gibt nicht an, welche Daten auf dem geändert wurden Datenbanktabelle, sie sagen nur, dass sich etwas geändert hat.

Schauen Sie sich GITHUB-Projekt an.

Wenn sich die erwarteten Aktualisierungen auf einen Index auswirken (und nur wenn), können Sie die Systemtabelle sys.dm_db_index_usage_stats Verwenden. , um die letzte Aktualisierung eines Index für die betreffende Tabelle zu ermitteln. Sie würden das Feld last_user_update Verwenden.

So erhalten Sie beispielsweise die zuletzt aktualisierten Tabellen:

select
    object_name(object_id) as OBJ_NAME, *
from
    sys.dm_db_index_usage_stats
where
    database_id = db_id(db_name())
order by
    dm_db_index_usage_stats.last_user_update desc

Oder um zu überprüfen, ob eine bestimmte Tabelle seit einem bestimmten Datum geändert wurde:

select
    case when count(distinct object_id) > 0 then 1 else 0 end as IS_CHANGED
from
    sys.dm_db_index_usage_stats
where
    database_id = db_id(db_name())
    and object_id = object_id('MY_TABLE_NAME')
    and last_user_update > '2016-02-18'
1
Geoff