Periksa perubahan pada tabel SQL Server?


142

Bagaimana saya bisa memonitor database SQL Server untuk perubahan tabel tanpa menggunakan pemicu atau memodifikasi struktur database dengan cara apa pun? Lingkungan pemrograman pilihan saya adalah .NET dan C #.

Saya ingin dapat mendukung SQL Server 2000 SP4 atau yang lebih baru. Aplikasi saya adalah visualisasi data untuk produk perusahaan lain. Basis pelanggan kami ada ribuan, jadi saya tidak ingin harus memasukkan persyaratan bahwa kami memodifikasi tabel vendor pihak ketiga di setiap instalasi.

Dengan "perubahan ke tabel" Maksudku perubahan data tabel, bukan perubahan pada struktur tabel.

Pada akhirnya, saya ingin perubahan untuk memicu suatu peristiwa dalam aplikasi saya, daripada harus memeriksa perubahan pada suatu interval.


Tindakan terbaik yang diberikan persyaratan saya (tidak ada pemicu atau modifikasi skema, SQL Server 2000 dan 2005) tampaknya menggunakan BINARY_CHECKSUMfungsi dalam T-SQL . Cara saya berencana untuk mengimplementasikannya adalah ini:

Setiap X detik jalankan kueri berikut:

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

Dan membandingkannya dengan nilai yang disimpan. Jika nilai telah berubah, buka baris tabel demi baris menggunakan kueri:

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

Dan bandingkan checksum yang dikembalikan dengan nilai yang disimpan.


3
Mereka tidak kebetulan memasang stempel waktu yang terakhir dimodifikasi pada baris mereka, bukan?
zmbq

Sebagai catatan, jika dukungan versi adalah SQL Server 2005 atau lebih baru. Saya akan melihat fitur Broker Layanan SQL Server.
Marco Guignard

Jawaban:


97

Lihatlah perintah CHECKSUM:

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

Itu akan mengembalikan nomor yang sama setiap kali dijalankan asalkan isi tabel tidak berubah. Lihat posting saya tentang ini untuk informasi lebih lanjut:

CHECKSUM

Inilah cara saya menggunakannya untuk membangun kembali dependensi cache ketika tabel berubah:
ASP.NET 1.1 dependensi cache database (tanpa pemicu)


2
Checksums dapat dan akan gagal pada akhirnya. Jika sistem Anda menerima bahwa dua set data yang berbeda akan menghasilkan checksum yang sama, maka Anda baik-baik saja. Untuk alasan itu, saya harus pindah dari checksum di sebagian besar sistem kami ...
LPains

@Lain Anda bisa tolong jelaskan pernyataan Anda?
petrosmm

1
@petrosmm Saya tidak yakin secara spesifik apa yang Anda ingin saya jelaskan, tapi saya akan coba. Bayangkan Anda memiliki tabel dengan beberapa ratus catatan, pada dasarnya Anda menghasilkan bilangan bulat sebagai checksum, seberapa sering itu akan bertabrakan? Dalam kasus saya, saya melakukan itu dengan sekitar 10 tabel, semuanya dengan ratusan catatan. Saya memiliki setidaknya satu tabrakan per hari. Periksa jawaban ini lainnya stackoverflow.com/questions/14450415/…
LPains

29

Sayangnya CHECKSUM tidak selalu berfungsi dengan baik untuk mendeteksi perubahan .

Ini hanya perhitungan primitif dan tidak ada perhitungan cyclic redundancy check (CRC).

Karenanya Anda tidak dapat menggunakannya untuk mendeteksi semua perubahan, mis. Perubahan simetris menghasilkan CHECKSUM yang sama!

E. g. solusi dengan CHECKSUM_AGG(BINARY_CHECKSUM(*))akan selalu memberikan 0 untuk semua 3 tabel dengan konten yang berbeda:


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
Itu sebenarnya bukan jawaban, itu adalah "saran Anda tidak berhasil".
kristianp

1
Ini dapat diperbaiki untuk data duplikat dengan menggunakan kata kunci DISINCT sebelum BINARY_CHECKSUM. Ada beberapa jebakan lain yang dibahas di sini tetapi skenario yang tidak umum.
pblack

25

Mengapa Anda tidak ingin menggunakan pemicu? Mereka adalah hal yang baik jika Anda menggunakannya dengan benar. Jika Anda menggunakannya sebagai cara untuk menegakkan integritas referensial saat itulah mereka beralih dari baik ke buruk. Tetapi jika Anda menggunakannya untuk pemantauan, mereka tidak benar-benar dianggap tabu.


20

Seberapa sering Anda perlu memeriksa perubahan dan seberapa besar (dalam hal ukuran baris) tabel dalam database? Jika Anda menggunakan CHECKSUM_AGG(BINARY_CHECKSUM(*))metode yang disarankan oleh John, itu akan memindai setiap baris dari tabel yang ditentukan. The NOLOCKpetunjuk membantu, tetapi pada database besar, Anda masih memukul setiap baris. Anda juga perlu menyimpan checksum untuk setiap baris sehingga Anda tahu ada yang berubah.

Sudahkah Anda mempertimbangkan untuk melakukan ini dari sudut yang berbeda? Jika Anda tidak ingin memodifikasi skema untuk menambahkan pemicu, (yang masuk akal, ini bukan database Anda), sudahkah Anda mempertimbangkan bekerja dengan vendor aplikasi yang membuat database?

Mereka dapat menerapkan API yang menyediakan mekanisme untuk memberi tahu aplikasi aksesori bahwa data telah berubah. Ini bisa sesederhana menulis ke tabel notifikasi yang mencantumkan tabel apa dan baris mana yang dimodifikasi. Itu bisa diimplementasikan melalui pemicu atau kode aplikasi. Dari pihak Anda, ti tidak masalah, satu-satunya masalah Anda akan memindai tabel notifikasi secara berkala. Kinerja yang dicapai pada database akan jauh lebih sedikit daripada memindai setiap baris untuk perubahan.

Bagian yang sulit adalah meyakinkan vendor aplikasi untuk mengimplementasikan fitur ini. Karena ini dapat ditangani sepenuhnya melalui SQL melalui pemicu, Anda bisa melakukan sebagian besar pekerjaan untuk mereka dengan menulis dan menguji pemicu dan kemudian membawa kode ke vendor aplikasi. Dengan meminta vendor mendukung pemicu, itu mencegah situasi di mana Anda menambahkan pemicu secara tidak sengaja menggantikan pemicu yang disediakan oleh vendor.


18

Sayangnya, saya tidak berpikir bahwa ada cara bersih untuk melakukan ini di SQL2000. Jika Anda mempersempit persyaratan Anda ke SQL Server 2005 (dan lebih baru), maka Anda berada dalam bisnis. Anda bisa menggunakan SQLDependencykelas di System.Data.SqlClient. Lihat Pemberitahuan Permintaan di SQL Server (ADO.NET) .


16

Memiliki pekerjaan DTS (atau pekerjaan yang dimulai oleh layanan windows) yang berjalan pada interval tertentu. Setiap kali dijalankan, ia mendapat informasi tentang tabel yang diberikan dengan menggunakan tabel sistem INFORMATION_SCHEMA , dan mencatat data ini dalam repositori data. Bandingkan data yang dikembalikan mengenai struktur tabel dengan data yang dikembalikan pada waktu sebelumnya. Jika berbeda, maka Anda tahu bahwa strukturnya telah berubah.

Contoh permintaan untuk mengembalikan informasi mengenai semua kolom dalam tabel ABC (idealnya mencantumkan hanya kolom dari tabel INFORMATION_SCHEMA yang Anda inginkan, daripada menggunakan * pilih ** seperti yang saya lakukan di sini):

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

Anda akan memantau kolom yang berbeda dan tampilan INFORMATION_SCHEMA tergantung pada bagaimana Anda mendefinisikan "perubahan ke tabel".


2
Pertanyaannya adalah tentang perubahan data tabel dan information_schema berisi skema (definisi kolom) dari tabel.
juga

13

Tebakan liar di sini: Jika Anda tidak ingin mengubah tabel pihak ketiga, dapatkah Anda membuat tampilan lalu meletakkan pemicu pada tampilan itu?


6

Periksa tanggal komit terakhir. Setiap basis data memiliki riwayat kapan setiap komit dibuat. Saya percaya ini adalah standar kepatuhan ACID.


1
Harap berikan cara yang terdokumentasi untuk mendapatkan informasi ini mencakup ke tabel di SQL Server
Martin Smith
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.