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




sql server data ultima modifica tabella (6)

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 alla luce dei miei requisiti (nessun trigger o modifica dello schema, SQL Server 2000 e 2005) sembra essere l'uso della funzione BINARY_CHECKSUM 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.


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".


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 metodo CHECKSUM_AGG(BINARY_CHECKSUM(*)) suggerito da John, eseguirà la scansione di ogni riga della tabella specificata. Il suggerimento NOLOCK 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 preso in considerazione l'idea 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, impedisce la situazione in cui l'aggiunta di un trigger sostituisce inavvertitamente un trigger fornito dal fornitore.


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 cache del database ASP.NET 1.1 (senza trigger)


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?


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. È possibile utilizzare la classe SQLDependency in System.Data.SqlClient . Vedere Notifiche di query in SQL Server (ADO.NET) .


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 esempio le modifiche simmetriche producono lo stesso CHECKSUM!

Per esempio. la soluzione con CHECKSUM_AGG(BINARY_CHECKSUM(*)) consegnerà 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!





rdbms