Verificare la presenza di modifiche a una tabella di SQL Server?


142

Come posso monitorare un database di SQL Server per le modifiche a una tabella senza utilizzare i trigger o modificare la struttura del database in alcun modo? Il mio ambiente di programmazione preferito è .NET e C #.

Vorrei poter supportare qualsiasi SQL Server 2000 SP4 o versioni successive. La mia applicazione è una visualizzazione di dati imbullonati per il prodotto di un'altra azienda. La nostra base di clienti è a migliaia, quindi non voglio inserire requisiti che modifichino la tabella del fornitore di terze parti ad ogni installazione.

Per "modifiche a una tabella" intendo modifiche ai dati della tabella, non modifiche alla struttura della tabella.

In definitiva, vorrei che la modifica attivasse un evento nella mia applicazione, invece di dover controllare le modifiche a intervalli.


Il miglior modo di agire dato i miei requisiti (nessun trigger o modifica dello schema, SQL Server 2000 e 2005) sembra essere quello di utilizzare la BINARY_CHECKSUMfunzione in T-SQL . Il modo in cui ho intenzione di implementare è questo:

Ogni X secondi esegue la seguente query:

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

E confrontalo con il valore memorizzato. Se il valore è stato modificato, scorrere la tabella riga per riga utilizzando la query:

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

E confronta i checksum restituiti con i valori memorizzati.


3
Non è capitato di mettere un timestamp modificato per ultimo sulle loro file, vero?
zmbq,

Per la cronaca, se il supporto della versione è SQL Server 2005 o più recente. Darò un'occhiata alla funzionalità di Service Broker di SQL Server.
Marco Guignard,

Risposte:


97

Dai un'occhiata al comando CHECKSUM:

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

Ciò restituirà lo stesso numero ogni volta che viene eseguito, purché il contenuto della tabella non sia cambiato. Vedi il mio post su questo per ulteriori informazioni:

CHECKSUM

Ecco come l'ho usato per ricostruire le dipendenze della cache quando le tabelle sono cambiate:
dipendenza della cache del database ASP.NET 1.1 (senza trigger)


2
I checksum possono e falliranno alla fine. Se il tuo sistema accetta che due diversi set di dati comporteranno lo stesso checksum, allora stai bene. Per questo motivo, ho dovuto abbandonare i checksum nella maggior parte dei nostri sistemi ...
LPains

@La pena puoi approfondire la tua dichiarazione?
petrosmm,

1
@petrosmm Non sono sicuro di cosa specificamente vuoi che io elabori, ma proverò. Immagina di avere una tabella con poche centinaia di record, essenzialmente generi un numero intero come checksum, con che frequenza si scontrerà? Nel mio caso, lo stavo facendo con circa 10 tabelle, tutte con centinaia di record. Ho avuto almeno una collisione al giorno. Controllare questo altra risposta stackoverflow.com/questions/14450415/...
LPains

29

Sfortunatamente CHECKSUM non funziona sempre correttamente per rilevare le modifiche .

È solo un checksum primitivo e nessun calcolo del controllo di ridondanza ciclico (CRC).

Pertanto non è possibile utilizzarlo per rilevare tutte le modifiche, ad es. Modifiche simmetriche producono lo stesso CHECKSUM!

Per esempio. la soluzione con CHECKSUM_AGG(BINARY_CHECKSUM(*))fornirà sempre 0 per tutte e 3 le tabelle con contenuto diverso:


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!


5
In realtà non è una risposta, è un "tuo suggerimento non funziona".
kristianp,

1
Questo può essere risolto per i dati duplicati utilizzando la parola chiave DISINCT prima del BINARY_CHECKSUM. Ci sono alcune altre insidie ​​discusse qui, ma non esattamente scenari comuni.
pblack,

25

Perché non vuoi usare i trigger? Sono una buona cosa se li usi correttamente. Se li usi come un modo per imporre l'integrità referenziale, cioè quando vanno di bene in male. Ma se li usi per il monitoraggio, non sono davvero considerati tabù.


20

Con quale frequenza è necessario verificare le modifiche e quanto sono grandi (in termini di dimensioni della riga) le tabelle nel database? Se si utilizza il CHECKSUM_AGG(BINARY_CHECKSUM(*))metodo suggerito da John, eseguirà la scansione di ogni riga della tabella specificata. Il NOLOCKsuggerimento aiuta, ma su un database di grandi dimensioni, stai ancora colpendo ogni riga. Dovrai anche archiviare il checksum per ogni riga in modo da dire che uno è cambiato.

Hai considerato di andare da questo punto di vista diverso? Se non si desidera modificare lo schema per aggiungere trigger (il che ha senso, non è il database), hai mai considerato di lavorare con il fornitore dell'applicazione che crea il database?

Potrebbero implementare un'API che fornisce un meccanismo per notificare alle app accessorie che i dati sono cambiati. Potrebbe essere semplice come scrivere in una tabella di notifica che elenca quale tabella e quale riga sono state modificate. Ciò potrebbe essere implementato tramite trigger o codice dell'applicazione. Da parte tua, non ti importerebbe, la tua unica preoccupazione sarebbe la scansione della tabella di notifica su base periodica. Il miglioramento delle prestazioni nel database sarebbe molto inferiore alla scansione di ogni riga alla ricerca di modifiche.

La parte difficile sarebbe convincere il fornitore dell'applicazione a implementare questa funzione. Dal momento che questo può essere gestito interamente tramite SQL tramite trigger, è possibile svolgere gran parte del lavoro scrivendo e testando i trigger e quindi portando il codice al fornitore dell'applicazione. Avendo il fornitore che supporta i trigger, previene la situazione in cui l'aggiunta di un trigger sostituisce inavvertitamente un trigger fornito dal fornitore.


18

Sfortunatamente, non penso che ci sia un modo pulito per farlo in SQL2000. Se restringi i tuoi requisiti a SQL Server 2005 (e versioni successive), sei in affari. Puoi usare la SQLDependencyclasse in System.Data.SqlClient. Vedere Notifiche di query in SQL Server (ADO.NET) .


16

Avere un lavoro DTS (o un lavoro avviato da un servizio Windows) che viene eseguito a un determinato intervallo. Ogni volta che viene eseguito, ottiene informazioni sulla tabella fornita utilizzando le tabelle INFORMATION_SCHEMA del sistema e registra questi dati nel repository di dati. Confrontare i dati restituiti relativi alla struttura della tabella con i dati restituiti la volta precedente. Se è diverso, allora sai che la struttura è cambiata.

Query di esempio per restituire informazioni su tutte le colonne della tabella ABC (elencando idealmente solo le colonne della tabella INFORMATION_SCHEMA che si desidera, invece di utilizzare * selezionare ** come faccio qui):

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

Monitoreresti colonne e viste INFORMATION_SCHEMA diverse a seconda di come definisci esattamente "modifiche a una tabella".


2
La domanda riguarda le modifiche ai dati della tabella e information_schema contiene lo schema (definizioni delle colonne) della tabella.
anche il

13

Indovina selvaggia qui: se non si desidera modificare le tabelle di terze parti, è possibile creare una vista e quindi attivare un trigger su quella vista?


6

Controlla la data dell'ultimo commit. Ogni database ha una cronologia di quando viene eseguito ogni commit. Credo che sia uno standard di conformità ACID.


1
Fornisci un modo documentato per ottenere queste informazioni nell'ambito di una tabella in SQL Server
Martin Smith,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.