SQL Server tablosundaki değişiklikleri kontrol etmek istiyor musunuz?


142

Tetikleyicileri kullanmadan veya veritabanının yapısını herhangi bir şekilde değiştirmeden bir SQL Server veritabanını tablodaki değişiklikler için nasıl izleyebilirim? Tercih ettiğim programlama ortamı .NET ve C #.

Herhangi bir SQL Server 2000 SP4 veya daha yeni sürümünü destekleyebilmek istiyorum . Uygulamam, başka bir şirketin ürünü için cıvatalı veri görselleştirmesidir. Müşteri tabanımız binlerce kişidir, bu nedenle her kurulumda üçüncü taraf satıcı tablosunu değiştirdiğimiz gereksinimleri koymak istemiyorum.

By "bir tabloya değiştirir" , masa verilere Acımasız değişikliklere tablo yapısına değiştirir değil.

Nihayetinde, değişikliğin belirli aralıklarla değişiklikleri kontrol etmek yerine, uygulamamda bir olayı tetiklemesini istiyorum.


Gereksinimlerim (tetikleyiciler veya şema değişikliği, SQL Server 2000 ve 2005 yok) göz önüne alındığında en iyi eylem, BINARY_CHECKSUMişlevi T-SQL'de kullanmak gibi görünüyor . Uygulamayı planladığım yol şudur:

Her X saniyede bir aşağıdaki sorgu çalıştırılır:

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

Ve bunu saklanan değerle karşılaştırın. Değer değiştiyse, sorguyu kullanarak tabloyu satır satır ilerleyin:

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

Ve döndürülen sağlama toplamlarını saklanan değerlerle karşılaştırın.


3
Satırlarına son değiştirilmiş bir zaman damgası koymadılar, değil mi?
zmbq

Kayıt için, sürüm desteği SQL Server 2005 veya daha yeni ise. SQL Server'ın Service Broker özelliğine bir göz atacağım.
Marco Guignard

Yanıtlar:


97

CHECKSUM komutuna bir göz atın:

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

Bu, tablo içeriği değişmediği sürece her çalıştırıldığında aynı sayıyı döndürür. Daha fazla bilgi için bu konudaki yazımı görün:

SAĞLAMA

Tablolar değiştiğinde önbellek bağımlılıklarını yeniden oluşturmak için şu şekilde kullandım:
ASP.NET 1.1 veritabanı önbellek bağımlılığı (tetikleyiciler olmadan)


2
Sağlama toplamları sonunda başarısız olur ve başarısız olur. Sisteminiz iki farklı veri kümesinin aynı sağlama toplamıyla sonuçlanacağını kabul ederse, iyi olduğunuzdan. Bu nedenle, sistemlerimizin çoğunda sağlama toplamlarından uzaklaşmak zorunda kaldım ...
LPains

@LPains lütfen açıklamanızı biraz açıklayabilir misiniz?
petrosmm

1
@petrosmm Özellikle neleri ayrıntılandırmamı istediğinizden emin değilim, ama deneyeceğim. Birkaç yüz kaydı olan bir tablonuz olduğunu düşünün, aslında bir sağlama toplamı olarak bir tamsayı oluşturdunuz, bu ne sıklıkta çarpışacak? Benim durumumda, bunu yüzlerce kayıt ile yaklaşık 10 tablo ile yapıyordum. Günde en az bir çarpışma yaşadım. Bu diğer yanıtı kontrol edin stackoverflow.com/questions/14450415/…
LPains

29

Maalesef CHECKSUM değişiklikleri tespit etmek için her zaman düzgün çalışmaz .

Yalnızca ilkel bir sağlama toplamıdır ve döngüsel artıklık denetimi (CRC) hesaplaması yoktur.

Bu nedenle, tüm değişiklikleri tespit etmek için kullanamazsınız, örneğin simetrik değişiklikler aynı CHECKSUM ile sonuçlanır!

Örneğin. ile çözüm, CHECKSUM_AGG(BINARY_CHECKSUM(*))farklı içeriğe sahip 3 tablonun tümü için her zaman 0 sağlar:


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
Bu aslında bir cevap değil, "öneriniz işe yaramıyor".
kristianp

1
Bu, BINARY_CHECKSUM öncesinde DISINCT anahtar sözcüğü kullanılarak çoğaltılan veriler için düzeltilebilir. Birkaç diğer tartışılan tuzaklar vardır burada ama tam olarak genel senaryolar.
pblack

25

Neden tetikleyicileri kullanmak istemiyorsunuz? Onları doğru kullanırsanız iyi bir şeydir. Bunları, iyilikten kötüye gittikleri zaman olan referans bütünlüğünü güçlendirmenin bir yolu olarak kullanırsanız. Ancak bunları izleme için kullanırsanız, gerçekten tabu olarak kabul edilmezler.


20

Ne sıklıkla değişiklikleri kontrol etmeniz gerekir ve veritabanındaki tablolar ne kadar büyüktür (satır boyutu açısından)? CHECKSUM_AGG(BINARY_CHECKSUM(*))John tarafından önerilen yöntemi kullanırsanız , belirtilen tablonun her satırını tarar. NOLOCKİpucu yardımcı olur, ancak büyük bir veritabanı üzerinde, yine her satır isabet. Ayrıca, her satır için sağlama toplamını saklamanız gerekir, böylece birinin değiştiğini söylersiniz.

Buna farklı bir açıdan gitmeyi düşündünüz mü? Tetikleyici eklemek için şemayı değiştirmek istemiyorsanız (bu bir anlam ifade eder, bu sizin veritabanınız değildir), veritabanını oluşturan uygulama satıcısıyla çalışmayı düşündünüz mü?

Aksesuar uygulamalarına verilerin değiştiğini bildirmek için bir mekanizma sağlayan bir API uygulayabilirler. Hangi tablonun ve hangi satırın değiştirildiğini listeleyen bir bildirim tablosuna yazmak kadar basit olabilir. Bu, tetikleyiciler veya uygulama kodu aracılığıyla uygulanabilir. Sizin açınızdan, ti önemli değil, tek endişeniz periyodik olarak bildirim tablosunu taramak olacaktır. Veritabanındaki isabet, her satırı değişiklikler için taramaktan çok daha az olacaktır.

Zor kısım, uygulama satıcısını bu özelliği uygulamaya ikna edecektir. Bu tamamen tetikleyiciler aracılığıyla SQL üzerinden işlenebildiğinden, tetikleyicileri yazıp test ederek ve ardından kodu uygulama satıcısına getirerek onlar için işin büyük bölümünü yapabilirsiniz. Satıcının tetikleyicileri desteklemesini sağlayarak, bir tetikleyici eklemenin, satıcı tarafından sağlanan bir tetikleyiciyi yanlışlıkla değiştirmesi durumunu önler.


18

Ne yazık ki, SQL2000 bunu yapmak için temiz bir yol olduğunu düşünmüyorum. Gereksinimlerinizi SQL Server 2005'e (ve daha yenisine) daraltırsanız, iş başındasınız demektir. İçindeki SQLDependencysınıfı kullanabilirsiniz System.Data.SqlClient. SQL Server'da (ADO.NET) Sorgu Bildirimleri'ne bakın .


16

Belirli bir aralıkta çalışan bir DTS işi (veya bir Windows hizmeti tarafından başlatılan bir iş) bulundurun. Her çalıştırıldığında, sistem BİLGİ_SCHEMA tablolarını kullanarak verilen tablo hakkında bilgi alır ve bu verileri veri havuzuna kaydeder. Tablonun yapısına ilişkin döndürülen verileri, önceki kez döndürülen verilerle karşılaştırın. Farklıysa, yapının değiştiğini bilirsiniz.

ABC tablosundaki tüm sütunlarla ilgili bilgileri döndürmek için örnek sorgu (ideal olarak, burada yaptığım gibi * select ** kullanmak yerine, BİLGİ_SCHEMA tablosundan istediğiniz sütunları listelemek):

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

"Tablodaki değişiklikleri" tam olarak nasıl tanımladığınıza bağlı olarak farklı sütunları ve BİLGİ_SCHEMA görünümlerini izlersiniz.


2
Soru tablo verilerindeki değişikliklerle ilgilidir ve information_schema tablonun şemasını (sütun tanımları) içerir.
çok

13

Vahşi tahmin burada: Üçüncü tarafın tablolarını değiştirmek istemiyorsanız, bir görünüm oluşturabilir ve ardından bu görünüme bir tetikleyici koyabilir misiniz?


6

Son teslim tarihini kontrol edin. Her veritabanının, her bir taahhüdün ne zaman yapıldığının geçmişi vardır. Bunun bir standart ACID uyumluluğu olduğuna inanıyorum.


1
Lütfen bu bilgileri SQL Server'daki bir tabloya dahil etmenin belgelenmiş bir yolunu sağlayın
Martin Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.