Verificar alterações em uma tabela do SQL Server?

142

Como posso monitorar um banco de dados do SQL Server para alterações em uma tabela sem usar gatilhos ou modificar a estrutura do banco de dados de alguma maneira? Meu ambiente de programação preferido é o .NET e C #.

Eu gostaria de poder oferecer suporte a qualquer SQL Server 2000 SP4 ou mais recente. Meu aplicativo é uma visualização de dados aparafusada para o produto de outra empresa. Nossa base de clientes está na casa dos milhares, por isso não quero exigir que modifiquemos a tabela de fornecedores terceirizados a cada instalação.

Por "alterações em uma tabela", quero dizer alterações nos dados da tabela, não alterações na estrutura da tabela.

Por fim, gostaria que a alteração acionasse um evento no meu aplicativo, em vez de ter que verificar alterações em um intervalo.


O melhor curso de ação, considerando meus requisitos (sem gatilhos ou modificação de esquema, SQL Server 2000 e 2005), parece ser o uso da BINARY_CHECKSUMfunção no T-SQL . A maneira que planejo implementar é esta:

A cada X segundos, execute a seguinte consulta:

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

E compare isso com o valor armazenado. Se o valor foi alterado, percorra a tabela linha por linha usando a consulta:

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

E compare as somas de verificação retornadas com os valores armazenados.

TimM
fonte
3
Eles não colocaram um carimbo de data e hora da última modificação em suas linhas, colocaram?
Zmbq
Para o registro, se o suporte à versão for SQL Server 2005 ou mais recente. Vou dar uma olhada no recurso Service Broker do SQL Server.
Marco Guignard

Respostas:

97

Dê uma olhada no comando CHECKSUM:

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

Isso retornará o mesmo número sempre que for executado, desde que o conteúdo da tabela não tenha sido alterado. Veja meu post sobre isso para obter mais informações:

CHECKSUM

Aqui está como eu o usei para reconstruir dependências de cache quando as tabelas foram alteradas:
Dependência de cache do banco de dados ASP.NET 1.1 (sem gatilhos)

Jon Galloway
fonte
2
As somas de verificação podem e falharão eventualmente. Se o seu sistema aceitar que dois conjuntos diferentes de dados resultarão na mesma soma de verificação, você estará bem. Por essa razão, eu tive que afastar-se de somas de verificação na maioria dos nossos sistemas ...
LPains
@LPains, você pode elaborar sua declaração?
25418 petrosmm
1
@petrosmm Não sei o que especificamente você quer que eu elabore, mas vou tentar. Imagine que você tem uma tabela com algumas centenas de registros, você basicamente gera um número inteiro como uma soma de verificação, com que frequência isso colidirá? No meu caso, eu fazia isso com cerca de 10 tabelas, todas com centenas de registros. Eu tive pelo menos uma colisão por dia. Verifique esta outra resposta stackoverflow.com/questions/14450415/…
LPains
29

Infelizmente, o CHECKSUM nem sempre funciona corretamente para detectar alterações .

É apenas uma soma de verificação primitiva e nenhum cálculo de verificação de redundância cíclica (CRC).

Portanto, você não pode usá-lo para detectar todas as alterações, por exemplo, alterações simétricas resultam no mesmo CHECKSUM!

Por exemplo. a solução CHECKSUM_AGG(BINARY_CHECKSUM(*))sempre fornecerá 0 para todas as 3 tabelas com conteúdo diferente:


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
fonte
5
Isso não é realmente uma resposta, é uma "sua sugestão não funciona".
precisa saber é
1
Isso pode ser remediado para dados duplicados usando a palavra-chave DISINCT antes do BINARY_CHECKSUM. Existem algumas outras armadilhas discutidas aqui, mas não cenários exatamente comuns.
pblack
25

Por que você não deseja usar gatilhos? Eles são bons se você os usar corretamente. Se você usá-los como uma maneira de impor a integridade referencial, é quando eles vão de bom a ruim. Mas se você usá-los para monitoramento, eles não são realmente considerados tabus.

Nick Berardi
fonte
20

Com que frequência você precisa verificar alterações e qual o tamanho (em termos de tamanho da linha) das tabelas no banco de dados? Se você usar o CHECKSUM_AGG(BINARY_CHECKSUM(*))método sugerido por John, ele verificará todas as linhas da tabela especificada. A NOLOCKdica ajuda, mas em um banco de dados grande, você ainda está acessando todas as linhas. Você também precisará armazenar a soma de verificação para cada linha para que você diga que uma foi alterada.

Você já pensou em fazer isso de um ângulo diferente? Se você não deseja modificar o esquema para adicionar gatilhos (o que faz sentido, não é o seu banco de dados), você já pensou em trabalhar com o fornecedor do aplicativo que faz o banco de dados?

Eles poderiam implementar uma API que fornece um mecanismo para notificar os aplicativos acessórios que os dados foram alterados. Pode ser tão simples quanto gravar em uma tabela de notificação que lista qual tabela e qual linha foi modificada. Isso pode ser implementado através de gatilhos ou código do aplicativo. Do seu lado, isso não importa, sua única preocupação seria verificar a tabela de notificação periodicamente. O desempenho atingido no banco de dados seria muito menor do que verificar todas as linhas em busca de alterações.

A parte difícil seria convencer o fornecedor do aplicativo a implementar esse recurso. Como isso pode ser tratado inteiramente através do SQL por meio de gatilhos, você pode fazer a maior parte do trabalho para eles escrevendo e testando os gatilhos e levando o código ao fornecedor do aplicativo. Ao fazer com que o fornecedor suporte os acionadores, evita a situação em que a adição de um acionador substitui inadvertidamente um acionador fornecido pelo fornecedor.

Chris Miller
fonte
18

Infelizmente, não acho que exista uma maneira limpa de fazer isso no SQL2000. Se você restringir seus requisitos ao SQL Server 2005 (e posterior), estará no negócio. Você pode usar a SQLDependencyclasse em System.Data.SqlClient. Consulte Notificações de consulta no SQL Server (ADO.NET) .

caryden
fonte
16

Tenha um trabalho DTS (ou um trabalho iniciado por um serviço do Windows) que seja executado em um determinado intervalo. Cada vez que é executado, ele obtém informações sobre a tabela especificada usando as tabelas sistema INFORMAÇÕES_SCHEMA e registra esses dados no repositório de dados. Compare os dados retornados em relação à estrutura da tabela com os dados retornados na hora anterior. Se for diferente, você saberá que a estrutura mudou.

Consulta de exemplo para retornar informações sobre todas as colunas da tabela ABC (idealmente listando apenas as colunas da tabela INFORMATION_SCHEMA que você deseja, em vez de usar * select ** como eu faço aqui):

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

Você monitoraria diferentes colunas e visualizações de INFORMAÇÕES_SCHEMA, dependendo de como exatamente define "alterações em uma tabela".

Yaakov Ellis
fonte
2
A pergunta é sobre alterações nos dados da tabela e information_schema contém o esquema (definições de coluna) da tabela.
também
13

Palpite aqui: Se você não deseja modificar as tabelas de terceiros, é possível criar uma visualização e acionar essa visualização?

Orion Edwards
fonte
6

Verifique a data da última confirmação. Todo banco de dados tem um histórico de quando cada confirmação é feita. Eu acredito que é um padrão de conformidade com ACID.

ECE
fonte
1
Por favor, forneça uma forma documentada de obter esta informação escopo para uma tabela no SQL Server
Martin Smith