Bagaimana cara merekam setiap perubahan baris dalam basis data secara umum disimpan?

10

Dalam proyek yang sedang saya kerjakan, setiap perubahan pada baris di beberapa tabel database harus dilacak untuk audit atau rollback lebih lanjut. Pasti mudah untuk menemukan siapa yang memodifikasi baris, dari mana alamat IP dan kapan, dan dapat mengembalikan versi sebelumnya.

Hal serupa digunakan misalnya oleh Stack Exchange. Ketika saya mengubah pertanyaan orang lain, adalah mungkin untuk menemukan bahwa saya mengubahnya, dan untuk mengembalikannya.

Apa teknik umum yang digunakan untuk menyimpan setiap perubahan ke objek dalam database , mengingat skema saya saat ini sebagian besar memiliki sifat yang sama (di bawah) dengan aplikasi bisnis rata-rata?

  • Objek memiliki ukuran yang relatif kecil: mungkin ada beberapa nvarchar(1000)contohnya, tetapi bukan gumpalan besar data biner, yang ini disimpan langsung pada disk, dan diakses secara langsung, dan tidak melalui Microsoft SQL filestream,
  • Beban basis data sangat rendah dan seluruh basis data ditangani oleh satu mesin virtual di server,
  • Akses ke versi sebelumnya tidak harus secepat akses ke versi terbaru, tetapi tetap harus up-to-date¹ dan tidak terlalu lambat².

<tl-dr>

Saya memikirkan kasus-kasus berikut, tetapi saya tidak memiliki pengalaman nyata dengan skenario semacam itu, jadi saya akan mendengar pendapat orang lain:

  1. Simpan segala sesuatu di tabel yang sama, bedakan baris dengan ID dan versi. IMO, itu benar-benar bodoh, dan akan cepat atau lambat akan terluka pada tingkat kinerja. Dengan pendekatan ini, juga tidak mungkin untuk mengatur tingkat keamanan yang berbeda untuk item terbaru dan jejak versi. Akhirnya, setiap permintaan akan lebih rumit untuk ditulis. Sebenarnya, untuk mengakses data terbaru, saya akan dipaksa untuk mengelompokkan semuanya berdasarkan ID dan mengambil, di setiap kelompok, versi terakhir.

  2. Simpan versi terbaru dalam satu tabel, dan, pada setiap perubahan, salin versi yang sudah usang ke tabel lain dalam skema lain. Kelemahannya adalah bahwa setiap kali, kami menyimpan setiap nilai, meskipun itu tidak berubah. Menetapkan nilai yang tidak berubah ke nullbukan solusi, karena saya juga harus melacak ketika nilai diubah ke nullatau dari null.

  3. Simpan versi terbaru dalam satu tabel, dan daftar properti yang diubah dengan nilai sebelumnya di tabel lain. Hal ini tampaknya memiliki dua kelemahan: yang paling penting adalah bahwa satu-satunya cara untuk memilah jenis heterogen dari nilai sebelumnya dalam kolom yang sama adalah memiliki binary(max). Yang kedua adalah, saya percaya, akan lebih sulit untuk menggunakan struktur seperti itu ketika menampilkan versi sebelumnya kepada pengguna.

  4. Lakukan hal yang sama seperti pada dua poin sebelumnya, tetapi simpan versi dalam database terpisah. Dari segi kinerja, mungkin menarik untuk menghindari memperlambat akses ke versi terbaru dengan memiliki versi sebelumnya di database yang sama; tetap, saya percaya bahwa ini adalah optimasi prematur dan harus dilakukan hanya jika ada bukti bahwa memiliki versi yang lebih lama dan terbaru dalam database yang sama adalah hambatan.

</tl-dr>


¹ Misalnya, akan tidak dapat diterima untuk menyimpan perubahan ke dalam file log, seperti yang dilakukan untuk log HTTP, dan menyiram data dari log ke database pada malam hari ketika beban server paling rendah. Informasi tentang berbagai versi harus segera tersedia atau segera; penundaan beberapa detik dapat diterima.

² Informasi tidak sering diakses dan hanya oleh kelompok pengguna tertentu, tetapi tetap saja, tidak dapat diterima untuk memaksa mereka menunggu selama 30 detik agar daftar versi ditampilkan. Sekali lagi, penundaan beberapa detik dapat diterima.

Arseni Mourzenko
sumber
3
Relevan: SQL Server Ubah Data Capture .
Nick Chammas

Jawaban:

8

Cara normal melakukan audit logging semacam ini adalah memiliki tabel bayangan dan mencatat perubahan dengan pemicu pada tabel dasar yang Anda audit. Tabel lain dapat ditempatkan pada disk fisik yang berbeda jika Anda perlu melakukannya untuk kinerja, dan Anda dapat menempatkan indeks pada mereka jika Anda perlu mendukung pengambilan data yang cepat.

Tabel akan memiliki struktur yang kira-kira sama dengan tabel asli Anda, tetapi akan memiliki kolom datetime ketika perubahan terjadi dan penanda untuk apakah baris dimasukkan, diubah atau dihapus. Mengurutkan versi dapat dilakukan dengan cap waktu.

Tanggal perubahan dapat dilakukan dengan membuat kolom datetime tidak nol dengan default getdate (); kolom pengguna audit akan menangkap pengguna dengan kolom bukan nol yang default ke Suser_Sname (). Dengan asumsi pengguna yang sebenarnya sedang berpura-pura dalam sesi ini akan menangkap identitas pengguna yang membuat perubahan.

Basis data tidak memiliki cara untuk mengetahui alamat IP yang menghubungkan ke server web. Aplikasi harus secara eksplisit menangkap dan mencatat alamat IP dengan transaksi.

Jika Anda memiliki sejumlah besar tabel yang ingin Anda audit, Anda dapat menggunakan metadata dari kamus data sistem untuk menghasilkan pemicu secara terprogram.

Solusi ini sejauh ini adalah yang terbaik karena beberapa alasan:

  • Itu menangkap setiap perubahan pada tabel, bukan hanya yang dibuat oleh aplikasi.

  • Tabel audit dapat diletakkan pada set disk yang berbeda untuk mengurangi beban I / O pada tabel utama Anda.

  • Anda bisa menggunakan tampilan berdasarkan gabungan tabel dan tabel log audit yang akan menampilkan seluruh riwayat termasuk versi saat ini.

  • Anda bisa mengindeks tabel log audit seperlunya sehingga pengguna audit dapat meminta mereka secara responsif. Seperti biasa, pemilihan indeks adalah tradeoff antara kinerja permintaan dan pembaruan overhead.

ConcernedOfTunbridgeWells
sumber
Anda mencoba untuk mengatakan jika saya punya 1000 tabel yang saya perlu mempertahankan log untuk setiap perubahan maka saya harus membuat 1000 tabel bayangan ya? dan 1000 pemicu untuk menangkap perubahan? jika ya maka itu adalah gagasan palsu ... kita dapat membuat tabel riwayat tunggal dan pemicu tunggal untuk menangkap & mencatat data yang diubah. kita dapat menyimpan data baris lama dan baru di tabel itu sebagai xml .... yang dilakukan banyak orang .... apakah saya jelas !!
Thomas
1
Untuk 1000 tabel, Anda menulis utlity yang membaca definisi dari kamus data sistem dan menghasilkan pemicu dan definisi tabel. Saya sudah melakukannya pada sistem dengan 560 tabel dan berfungsi dengan baik.
ConcernedOfTunbridgeWells
0

Saya tahu banyak sistem CMS (termasuk Wordpress) yang menggunakan tabel tunggal untuk menyimpan semua versi data. Tetapi sekali lagi, mereka hanya perlu melakukan ini untuk tabel yang memiliki posting blog. Lihat struktur database Wordpress .

Juga, jumlah catatan dan jumlah revisi yang dilewati setiap baris akan memainkan peran penting dalam keputusan Anda.

Dharmendar Kumar 'DK'
sumber
0

Tentang versi CMS; untuk drupal ia membuat tabel khusus untuk setiap bidang entitas yang menyimpan nilai lama; konsep seperti itu memungkinkan Anda memanipulasi data Anda dengan baik tetapi saya pikir itu mahal, solusi saya sendiri adalah dengan mengubah objek saya ke format xml dan menyimpannya sebagai string dengan bidang lain (changetime, id ...)

Bourkadi
sumber