Nach Änderungen an einer SQL Server-Tabelle suchen?

141

Wie kann ich eine SQL Server-Datenbank auf Änderungen an einer Tabelle überwachen, ohne Trigger zu verwenden oder die Struktur der Datenbank in irgendeiner Weise zu ändern? Meine bevorzugte Programmierumgebung ist .NET und C #.

Ich möchte in der Lage sein, SQL Server 2000 SP4 oder neuer zu unterstützen. Meine Anwendung ist eine integrierte Datenvisualisierung für das Produkt eines anderen Unternehmens. Unser Kundenstamm liegt bei Tausenden, daher möchte ich nicht bei jeder Installation die Anforderungen stellen müssen, dass wir die Tabelle des Drittanbieters ändern.

Mit "Änderungen an einer Tabelle" meine ich Änderungen an Tabellendaten, nicht Änderungen an der Tabellenstruktur.

Letztendlich möchte ich, dass die Änderung ein Ereignis in meiner Anwendung auslöst, anstatt in regelmäßigen Abständen nach Änderungen suchen zu müssen.


Die beste Vorgehensweise angesichts meiner Anforderungen (keine Trigger oder Schemaänderungen, SQL Server 2000 und 2005) scheint darin zu bestehen, die BINARY_CHECKSUMFunktion in T-SQL zu verwenden . Die Art und Weise, wie ich sie implementieren möchte, ist folgende:

Führen Sie alle X Sekunden die folgende Abfrage aus:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*))
FROM sample_table
WITH (NOLOCK);

Und vergleichen Sie das mit dem gespeicherten Wert. Wenn sich der Wert geändert hat, gehen Sie die Tabelle Zeile für Zeile mit der folgenden Abfrage durch:

SELECT row_id, BINARY_CHECKSUM(*)
FROM sample_table
WITH (NOLOCK);

Und vergleichen Sie die zurückgegebenen Prüfsummen mit gespeicherten Werten.

TimM
quelle
3
Sie haben nicht zufällig einen zuletzt geänderten Zeitstempel in ihre Zeilen eingefügt, oder?
Zmbq
Für den Datensatz, wenn die Versionsunterstützung SQL Server 2005 oder neuer ist. Ich werde einen Blick auf die Service Broker-Funktion von SQL Server werfen.
Marco Guignard

Antworten:

97

Schauen Sie sich den Befehl CHECKSUM an:

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM sample_table WITH (NOLOCK);

Dies gibt bei jeder Ausführung dieselbe Nummer zurück, solange sich der Tabelleninhalt nicht geändert hat. Weitere Informationen finden Sie in meinem Beitrag dazu:

CHECKSUM

So habe ich es verwendet, um Cache-Abhängigkeiten wiederherzustellen, wenn sich Tabellen geändert haben:
ASP.NET 1.1-Datenbank-Cache-Abhängigkeit (ohne Trigger)

Jon Galloway
quelle
2
Prüfsummen können und werden irgendwann scheitern. Wenn Ihr System akzeptiert, dass zwei verschiedene Datensätze dieselbe Prüfsumme ergeben, ist alles in Ordnung. Aus diesem Grund musste ich mich in den meisten unserer Systeme von Prüfsummen
entfernen
@LPains können Sie bitte Ihre Aussage näher erläutern?
Petrosmm
1
@petrosmm Ich bin mir nicht sicher, was genau ich ausarbeiten soll, aber ich werde es versuchen. Stellen Sie sich vor, Sie haben eine Tabelle mit einigen hundert Datensätzen. Sie generieren im Wesentlichen eine Ganzzahl als Prüfsumme. Wie oft wird diese kollidieren? In meinem Fall habe ich das mit ungefähr 10 Tabellen gemacht, alle mit Hunderten von Datensätzen. Ich hatte mindestens eine Kollision pro Tag. Überprüfen Sie diese andere Antwort stackoverflow.com/questions/14450415/…
LPains
29

Leider funktioniert CHECKSUM nicht immer richtig, um Änderungen zu erkennen .

Es handelt sich nur um eine primitive Prüfsumme und keine CRC-Berechnung (Cyclic Redundancy Check).

Daher können Sie damit nicht alle Änderungen erkennen, z. B. führen symmetrische Änderungen zu derselben CHECKSUM!

Z.B. Die Lösung mit CHECKSUM_AGG(BINARY_CHECKSUM(*))liefert immer 0 für alle 3 Tabellen mit unterschiedlichem Inhalt:


SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM 
(
  SELECT 1 as numA, 1 as numB
  UNION ALL
  SELECT 1 as numA, 1 as numB
)  q
-- delivers 0!

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 1 as numA, 2 as numB UNION ALL SELECT 1 as numA, 2 as numB ) q -- delivers 0!

SELECT CHECKSUM_AGG(BINARY_CHECKSUM(*)) FROM ( SELECT 0 as numA, 0 as numB UNION ALL SELECT 0 as numA, 0 as numB ) q -- delivers 0!

BitLauncher
quelle
5
Das ist eigentlich keine Antwort, es ist ein "Ihr Vorschlag funktioniert nicht".
Kristianp
1
Dies kann für doppelte Daten mithilfe des Schlüsselworts DISINCT vor BINARY_CHECKSUM behoben werden. Es gibt einige andere Fallstricke, die hier diskutiert werden, aber nicht gerade häufige Szenarien.
Schwarz
25

Warum möchten Sie keine Trigger verwenden? Sie sind eine gute Sache, wenn Sie sie richtig verwenden. Wenn Sie sie als Mittel zur Durchsetzung der referenziellen Integrität verwenden, wechseln sie von gut zu schlecht. Wenn Sie sie jedoch zur Überwachung verwenden, gelten sie nicht wirklich als Tabu.

Nick Berardi
quelle
20

Wie oft müssen Sie nach Änderungen suchen und wie groß (in Bezug auf die Zeilengröße) sind die Tabellen in der Datenbank? Wenn Sie die CHECKSUM_AGG(BINARY_CHECKSUM(*))von John vorgeschlagene Methode verwenden, wird jede Zeile der angegebenen Tabelle gescannt. Der NOLOCKHinweis hilft, aber in einer großen Datenbank treffen Sie immer noch jede Zeile. Sie müssen auch die Prüfsumme für jede Zeile speichern, damit Sie feststellen können, dass sich eine geändert hat.

Haben Sie darüber nachgedacht, dies aus einem anderen Blickwinkel zu betrachten? Wenn Sie das Schema nicht ändern möchten, um Trigger hinzuzufügen (was sinnvoll ist, es ist nicht Ihre Datenbank), haben Sie darüber nachgedacht, mit dem Anwendungsanbieter zusammenzuarbeiten, der die Datenbank erstellt?

Sie könnten eine API implementieren, die einen Mechanismus zum Benachrichtigen von Zubehör-Apps bereitstellt, wenn sich Daten geändert haben. Es könnte so einfach sein, in eine Benachrichtigungstabelle zu schreiben, in der aufgeführt ist, welche Tabelle und welche Zeile geändert wurden. Dies könnte durch Trigger oder Anwendungscode implementiert werden. Von Ihrer Seite aus wäre das egal, Ihr einziges Anliegen wäre es, die Benachrichtigungstabelle regelmäßig zu scannen. Der Leistungseinbruch in der Datenbank wäre weitaus geringer als das Scannen jeder Zeile nach Änderungen.

Der schwierige Teil wäre, den Anwendungsanbieter davon zu überzeugen, diese Funktion zu implementieren. Da dies vollständig über SQL über Trigger erledigt werden kann, können Sie den Großteil der Arbeit für sie erledigen, indem Sie die Trigger schreiben und testen und dann den Code zum Anwendungsanbieter bringen. Indem der Anbieter die Trigger unterstützt, wird verhindert, dass das Hinzufügen eines Triggers versehentlich einen vom Anbieter bereitgestellten Trigger ersetzt.

Chris Miller
quelle
18

Leider glaube ich nicht, dass es in SQL2000 einen sauberen Weg gibt, dies zu tun. Wenn Sie Ihre Anforderungen auf SQL Server 2005 (und höher) beschränken, sind Sie im Geschäft. Sie können die SQLDependencyKlasse in verwenden System.Data.SqlClient. Siehe Abfragebenachrichtigungen in SQL Server (ADO.NET) .

Caryden
quelle
16

Haben Sie einen DTS-Job (oder einen Job, der von einem Windows-Dienst gestartet wird), der in einem bestimmten Intervall ausgeführt wird. Bei jeder Ausführung werden mithilfe der Systemtabellen INFORMATION_SCHEMA Informationen zur angegebenen Tabelle abgerufen und diese Daten im Datenrepository aufgezeichnet. Vergleichen Sie die Daten, die bezüglich der Struktur der Tabelle zurückgegeben wurden, mit den Daten, die beim vorherigen Mal zurückgegeben wurden. Wenn es anders ist, wissen Sie, dass sich die Struktur geändert hat.

Beispielabfrage zur Rückgabe von Informationen zu allen Spalten in Tabelle ABC (im Idealfall werden nur die Spalten aus der Tabelle INFORMATION_SCHEMA aufgelistet, die Sie möchten, anstatt wie hier * select ** zu verwenden):

select * from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'ABC'

Sie würden verschiedene Spalten und INFORMATION_SCHEMA-Ansichten überwachen, je nachdem, wie genau Sie "Änderungen an einer Tabelle" definieren.

Yaakov Ellis
quelle
2
Die Frage bezieht sich auf Änderungen in Tabellendaten und information_schema enthält Schema (Spaltendefinitionen) der Tabelle.
Auch
13

Wilde Vermutung hier: Wenn Sie die Tabellen von Drittanbietern nicht ändern möchten, können Sie eine Ansicht erstellen und dann einen Auslöser für diese Ansicht setzen?

Orion Edwards
quelle
6

Überprüfen Sie das letzte Festschreibungsdatum. Jede Datenbank hat einen Verlauf, wann jedes Commit durchgeführt wird. Ich glaube, es ist ein Standard für die Einhaltung von Säuren.

ECE
quelle
1
Bitte geben Sie eine dokumentierte Möglichkeit an, diese Informationen in eine Tabelle in SQL Server zu übertragen
Martin Smith