Rechercher les modifications apportées à une table SQL Server?

142

Comment puis-je surveiller une base de données SQL Server pour les modifications apportées à une table sans utiliser de déclencheurs ou modifier la structure de la base de données de quelque manière que ce soit? Mon environnement de programmation préféré est .NET et C #.

J'aimerais pouvoir prendre en charge n'importe quel SQL Server 2000 SP4 ou plus récent. Mon application est une visualisation de données complémentaire pour le produit d'une autre entreprise. Notre base de clients se chiffre par milliers, je ne veux donc pas avoir à exiger que nous modifions la table du fournisseur tiers à chaque installation.

Par «modifications apportées à une table», j'entends des modifications des données de table, pas des modifications de la structure de la table.

En fin de compte, j'aimerais que la modification déclenche un événement dans mon application, au lieu d'avoir à vérifier les modifications à intervalles réguliers.


Le meilleur plan d'action étant donné mes besoins (pas de déclencheurs ou de modification de schéma, SQL Server 2000 et 2005) semble être d'utiliser la BINARY_CHECKSUMfonction dans T-SQL . La façon dont je prévois de mettre en œuvre est la suivante:

Toutes les X secondes, exécutez la requête suivante:

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

Et comparez cela à la valeur stockée. Si la valeur a changé, parcourez le tableau ligne par ligne à l'aide de la requête:

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

Et comparez les sommes de contrôle renvoyées aux valeurs stockées.

TimM
la source
3
Ils n'ont pas mis un horodatage de dernière modification sur leurs lignes, n'est-ce pas?
zmbq
Pour mémoire, si la prise en charge de la version est SQL Server 2005 ou plus récente. Je vais jeter un œil sur la fonctionnalité Service Broker de SQL Server.
Marco Guignard

Réponses:

97

Jetez un œil à la commande CHECKSUM:

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

Cela renverra le même nombre à chaque exécution tant que le contenu de la table n'a pas changé. Voir mon article à ce sujet pour plus d'informations:

CHECKSUM

Voici comment je l'ai utilisé pour reconstruire les dépendances du cache lorsque les tables ont changé:
Dépendance du cache de base de données ASP.NET 1.1 (sans déclencheurs)

Jon Galloway
la source
2
Les sommes de contrôle peuvent échouer et finiront par échouer. Si votre système accepte que deux ensembles de données différents aboutissent à la même somme de contrôle, alors tout va bien. Pour cette raison, j'ai dû m'éloigner des sommes de contrôle dans la plupart de nos systèmes ...
LPains
@LPains pouvez-vous s'il vous plaît élaborer sur votre déclaration?
petrosmm
1
@petrosmm Je ne sais pas exactement ce que vous voulez que j'élabore, mais je vais essayer. Imaginez que vous ayez une table avec quelques centaines d'enregistrements, vous générez essentiellement un entier comme somme de contrôle, à quelle fréquence cela va-t-il entrer en collision? Dans mon cas, je faisais cela avec environ 10 tables, toutes avec des centaines d'enregistrements. J'ai eu au moins une collision par jour. Vérifiez cette autre réponse stackoverflow.com/questions/14450415/…
LPains
29

Malheureusement, CHECKSUM ne fonctionne pas toujours correctement pour détecter les changements .

Il ne s'agit que d'une somme de contrôle primitive et d'aucun calcul de contrôle de redondance cyclique (CRC).

Par conséquent, vous ne pouvez pas l'utiliser pour détecter tous les changements, par exemple les changements symétriques donnent le même CHECKSUM!

Par exemple. la solution avec CHECKSUM_AGG(BINARY_CHECKSUM(*))fournira toujours 0 pour les 3 tables avec un contenu différent:


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
la source
5
Ce n'est pas vraiment une réponse, c'est un "votre suggestion ne fonctionne pas".
kristianp
1
Cela peut être résolu pour les données dupliquées en utilisant le mot clé DISINCT avant BINARY_CHECKSUM. Il y a quelques autres pièges discutés ici, mais pas exactement des scénarios courants.
pblack
25

Pourquoi ne voulez-vous pas utiliser de déclencheurs? Ils sont une bonne chose si vous les utilisez correctement. Si vous les utilisez comme moyen de renforcer l'intégrité référentielle, c'est à ce moment-là qu'ils vont de bon à mauvais. Mais si vous les utilisez pour la surveillance, ils ne sont pas vraiment considérés comme tabous.

Nick Berardi
la source
20

À quelle fréquence devez-vous vérifier les modifications et quelle est la taille (en termes de taille de ligne) des tables de la base de données? Si vous utilisez la CHECKSUM_AGG(BINARY_CHECKSUM(*))méthode suggérée par John, il analysera chaque ligne de la table spécifiée. L' NOLOCKindice aide, mais sur une grande base de données, vous frappez toujours chaque ligne. Vous devrez également stocker la somme de contrôle pour chaque ligne afin que vous en disiez qu'une a changé.

Avez-vous envisagé de procéder sous un angle différent? Si vous ne souhaitez pas modifier le schéma pour ajouter des déclencheurs (ce qui est logique, ce n'est pas votre base de données), avez-vous envisagé de travailler avec le fournisseur d'application qui crée la base de données?

Ils pourraient implémenter une API qui fournit un mécanisme pour notifier aux applications accessoires que les données ont changé. Cela peut être aussi simple que d'écrire dans une table de notification qui répertorie quelle table et quelle ligne ont été modifiées. Cela pourrait être mis en œuvre via des déclencheurs ou du code d'application. De votre côté, cela n'a pas d'importance, votre seule préoccupation serait de scanner régulièrement le tableau des notifications. La performance atteinte sur la base de données serait bien inférieure à l'analyse de chaque ligne pour les modifications.

Le plus dur serait de convaincre le fournisseur de l'application d'implémenter cette fonctionnalité. Étant donné que cela peut être géré entièrement via SQL via des déclencheurs, vous pouvez effectuer l'essentiel du travail pour eux en écrivant et en testant les déclencheurs, puis en apportant le code au fournisseur de l'application. En demandant au fournisseur de prendre en charge les déclencheurs, cela empêche la situation où l'ajout d'un déclencheur remplace par inadvertance un déclencheur fourni par le fournisseur.

Chris Miller
la source
18

Malheureusement, je ne pense pas qu'il existe un moyen propre de le faire dans SQL2000. Si vous limitez vos exigences à SQL Server 2005 (et versions ultérieures), vous êtes en affaires. Vous pouvez utiliser la SQLDependencyclasse dans System.Data.SqlClient. Consultez Notifications de requête dans SQL Server (ADO.NET) .

caryden
la source
16

Avoir un travail DTS (ou un travail démarré par un service Windows) qui s'exécute à un intervalle donné. Chaque fois qu'il est exécuté, il obtient des informations sur la table donnée à l'aide des tables système INFORMATION_SCHEMA et enregistre ces données dans le référentiel de données. Comparez les données renvoyées concernant la structure de la table avec les données renvoyées la fois précédente. Si c'est différent, vous savez que la structure a changé.

Exemple de requête pour renvoyer des informations concernant toutes les colonnes de la table ABC (idéalement ne listant que les colonnes de la table INFORMATION_SCHEMA que vous souhaitez, au lieu d'utiliser * select ** comme je le fais ici):

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

Vous surveilleriez différentes colonnes et vues INFORMATION_SCHEMA en fonction de la manière exacte dont vous définissez les «modifications apportées à une table».

Yaakov Ellis
la source
2
La question concerne les modifications des données de la table et information_schema contient le schéma (définitions de colonne) de la table.
trop
13

Imaginez ici: si vous ne souhaitez pas modifier les tables du tiers, pouvez-vous créer une vue, puis mettre un déclencheur sur cette vue?

Orion Edwards
la source
6

Vérifiez la dernière date de validation. Chaque base de données a un historique du moment où chaque validation est effectuée. Je crois que c'est une norme de conformité ACID.

ECE
la source
1
Veuillez fournir un moyen documenté d'obtenir ces informations étendues à une table dans SQL Server
Martin Smith