Desain database untuk logging audit

151

Setiap kali saya perlu mendesain database baru, saya menghabiskan banyak waktu memikirkan bagaimana saya harus mengatur skema database untuk menyimpan log audit dari perubahan.

Beberapa pertanyaan telah diajukan di sini tentang ini, tetapi saya tidak setuju bahwa ada satu pendekatan terbaik untuk semua skenario:

Saya juga menemukan artikel menarik tentang Mempertahankan Log Perubahan Database yang mencoba membuat daftar pro dan kontra dari setiap pendekatan. Itu ditulis dengan sangat baik dan memiliki informasi yang menarik, tetapi itu membuat keputusan saya lebih sulit.

Pertanyaan saya adalah: Apakah ada referensi yang dapat saya gunakan, mungkin buku atau sesuatu seperti pohon keputusan yang dapat saya rujuk untuk memutuskan cara mana yang harus saya gunakan berdasarkan beberapa variabel input, seperti:

  • Kematangan skema basis data
  • Bagaimana log akan ditanyakan
  • Probabilitas bahwa itu akan perlu untuk membuat ulang catatan
  • Yang lebih penting: menulis atau membaca kinerja
  • Sifat nilai-nilai yang sedang dicatat (string, angka, gumpalan)
  • Ruang penyimpanan tersedia

Pendekatan yang saya tahu adalah:

1. Tambahkan kolom untuk tanggal dan pengguna yang dibuat dan dimodifikasi

Contoh tabel:

  • Indo
  • value_1
  • value_2
  • value_3
  • Created_date
  • tanggal yang diubah
  • dibuat oleh
  • modified_by

Kontra utama: Kami kehilangan sejarah modifikasi. Tidak dapat mengembalikan setelah komit.

2. Masukkan hanya tabel

Contoh tabel :

  • Indo
  • value_1
  • value_2
  • value_3
  • dari
  • untuk
  • dihapus (Boolean)
  • pengguna

Kontra utama: Bagaimana cara memperbarui kunci asing? Dibutuhkan ruang besar

3. Buat tabel sejarah terpisah untuk setiap tabel

Contoh tabel sejarah:

  • Indo
  • value_1
  • value_2
  • value_3
  • value_4
  • pengguna
  • dihapus (Boolean)
  • cap waktu

Kontra utama: Perlu menduplikasi semua tabel yang diaudit. Jika skema berubah, maka akan diperlukan juga untuk memigrasi semua log.

4. Buat Tabel Riwayat Konsolidasi untuk Semua Tabel

Contoh tabel sejarah:

  • table_name
  • bidang
  • pengguna
  • nilai baru
  • dihapus (Boolean)
  • cap waktu

Kontra utama: Apakah saya dapat membuat ulang catatan (kembalikan) jika diperlukan dengan mudah? Kolom new_value harus berupa string besar sehingga dapat mendukung semua jenis kolom yang berbeda.

jbochi
sumber
1
dan bagaimana dengan menggunakan database histori alih-alih tabel?
Jowen
Mungkin Anda bisa memeriksa desain github.com/airblade/paper_trail
zx1986
Apakah ini ide yang buruk untuk mencatat semua (wajib) query yang dieksekusi apa adanya?
Dinushan

Jawaban:

87

Salah satu metode yang digunakan oleh beberapa platform wiki adalah memisahkan data pengidentifikasian dan konten yang Anda audit. Ini menambah kerumitan, tetapi Anda berakhir dengan jejak audit dari catatan lengkap, bukan hanya daftar bidang yang diedit yang kemudian harus Anda hancurkan untuk memberi pengguna gambaran tentang seperti apa rekaman lama itu.

Jadi misalnya, jika Anda memiliki tabel bernama Peluang untuk melacak penawaran penjualan, Anda sebenarnya akan membuat dua tabel terpisah:

Peluang
Opportunities_Content (atau sesuatu seperti itu)

The Peluang tabel akan memiliki informasi akan Anda gunakan untuk secara unik mengidentifikasi catatan dan akan rumah kunci utama Anda akan referensi untuk hubungan kunci asing Anda. The Opportunities_Content meja akan menahan semua bidang pengguna Anda dapat mengubah dan yang Anda ingin tetap audit trail. Setiap catatan dalam tabel Konten akan mencakup PK-nya sendiri dan data yang diubah oleh dan tanggal yang dimodifikasi. The Peluang meja akan mencakup referensi untuk versi saat ini serta informasi tentang kapan rekor utama awalnya diciptakan dan oleh siapa.

Berikut ini contoh sederhana:

CREATE TABLE dbo.Page(  
    ID int PRIMARY KEY,  
    Name nvarchar(200) NOT NULL,  
    CreatedByName nvarchar(100) NOT NULL, 
    CurrentRevision int NOT NULL, 
    CreatedDateTime datetime NOT NULL

Dan isinya:

CREATE TABLE dbo.PageContent(
    PageID int NOT NULL,
    Revision int NOT NULL,
    Title nvarchar(200) NOT NULL,
    User nvarchar(100) NOT NULL,
    LastModified datetime NOT NULL,
    Comment nvarchar(300) NULL,
    Content nvarchar(max) NOT NULL,
    Description nvarchar(200) NULL

Saya mungkin akan membuat PK dari tabel isi kunci multi-kolom dari PageID dan Revisi asalkan Revisi adalah tipe identitas. Anda akan menggunakan kolom Revisi sebagai FK. Anda kemudian menarik catatan konsolidasi dengan BERGABUNG seperti ini:

SELECT * FROM Page
JOIN PageContent ON CurrentRevision = Revision AND ID = PageID

Mungkin ada beberapa kesalahan di sana ... ini di atas kepala saya. Ini seharusnya memberi Anda gambaran tentang pola alternatif.

Josh Anderson
sumber
10
Dalam hal pendekatan audit yang baik tetapi untuk produksi akan membutuhkan banyak waktu untuk mengembangkan tabel audit terpisah untuk setiap tabel dalam database, penulisan pemicu untuk setiap tabel untuk menangkap perubahan dan menulisnya ke meja audit. Lebih jauh lagi, tantangan besar dalam mengembangkan laporan audit tunggal untuk semua tabel karena setiap tabel audit memiliki struktur yang berbeda.
asim-ishaq
11
Jika menulis dan memelihara skrip untuk setiap tabel merupakan masalah bagi organisasi yang bermaksud untuk mengelola database yang diaudit, saya tentu akan merekomendasikan agar mereka mempekerjakan DBA yang berpengalaman atau insinyur-perangkat lunak yang sangat fleksibel dan sangat berpengalaman-insinyur dengan pengalaman yang memadai membuat database yang diaudit. .
Hardryv
1
Apakah benar itu PageContent.PageIDuntuk FK Page.IDdan Page.CurrentRevisionFK PageContent.Revision? Apakah ketergantungan ini benar-benar melingkar?
2
Saya telah memilih karena tidak membahas alternatif yang disebutkan. Ini memberikan opsi lain yang merupakan solusi yang sangat spesifik untuk use case yang sangat spesifik. Tapi saya melihat manfaat dari desain yang disarankan
acteon
1
Saya bisa memikirkan sangat sedikit bidang yang bisa saya katakan dengan percaya diri tidak akan berubah sehingga semua tabel "utama" untuk setiap entitas akhirnya hanya menjadi id, revision_id; lebih dari tabel persimpangan, sungguh. Ini terasa agak bau bagi saya. Apa keuntungannya dibandingkan pendekatan 3 dalam OP (tabel sejarah per tabel yang diaudit)?
Kenmore
14

Jika Anda menggunakan SQL Server 2008, Anda mungkin harus mempertimbangkan Ubah Data Capture. Ini baru untuk tahun 2008 dan dapat menghemat banyak pekerjaan.

Randy Minder
sumber
di sini adalah tautan ke info pelacakan perubahan SQL 2012. msdn.microsoft.com/en-us/library/bb933994.aspx +1 untuk menggunakan fungsionalitas bawaan , tidak ada gunanya menemukan kembali roda.
Chris
4
@ Chris apakah Anda pernah menggunakannya sendiri? Memang, itu melacak segalanya ... tetapi bisa mendapatkan informasi yang bermanfaat darinya adalah cerita lain. Tidak dapat menggunakan roda traktor untuk sepeda saya.
Jowen
Ini benar - benar luar biasa. Tetapi jika Anda hanya memiliki SQL Server edisi standar , seperti saya, Anda kurang beruntung: "Ubah tangkapan data hanya tersedia di edisi Enterprise , Developer , dan Evaluasi Perusahaan ".
Brad Turek
6

Saya tidak tahu referensi apa pun, tetapi saya yakin seseorang telah menulis sesuatu.

Namun, jika tujuannya hanya untuk memiliki catatan tentang apa yang terjadi - penggunaan log audit yang paling khas - maka mengapa tidak menyimpan semuanya:

timestamp
username
ip_address
procedureName (if called from a stored procedure)
database
table
field
accesstype (insert, delete, modify)
oldvalue
newvalue

Agaknya ini dipertahankan oleh pemicu.

wallyk
sumber
Saya tidak tahu cara mendapatkan itu di dalam server database, tapi tentu saja itu bisa dilakukan dari luar cukup mudah.
wallyk
5
Menurut saya ini adalah pola desain yang sama dengan opsi ke-4 yang diperlihatkan dalam pertanyaan awal.
givanse
3

Kami akan membuat contoh database kecil untuk aplikasi blogging. Diperlukan dua tabel:

blog: menyimpan ID pos unik, judul, konten, dan bendera yang dihapus. audit: menyimpan serangkaian perubahan historis dasar dengan ID rekaman, ID posting blog, tipe perubahan (BARU, EDIT atau HAPUS) dan tanggal / waktu perubahan itu. SQL berikut ini membuat blogdan mengindeks kolom yang dihapus:

CREATE TABLE `blog` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `title` text,
    `content` text,
    `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0',
    PRIMARY KEY (`id`),
    KEY `ix_deleted` (`deleted`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='Blog posts';

SQL berikut ini membuat audittabel. Semua kolom diindeks dan kunci asing didefinisikan untuk audit.blog_id yang merujuk blog.id. Karenanya, ketika kita secara fisik HAPUS entri blog, riwayat audit lengkapnya juga dihapus.

CREATE TABLE `audit` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `blog_id` mediumint(8) unsigned NOT NULL,
    `changetype` enum('NEW','EDIT','DELETE') NOT NULL,
    `changetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `ix_blog_id` (`blog_id`),
    KEY `ix_changetype` (`changetype`),
    KEY `ix_changetime` (`changetime`),
    CONSTRAINT `FK_audit_blog_id` FOREIGN KEY (`blog_id`) REFERENCES `blog` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
ajit
sumber
2

Saya pikir tidak ada yang seperti pohon keputusan. Karena beberapa pro dan kontra (atau persyaratan) tidak benar-benar dapat dihitung. Bagaimana Anda mengukur Kematangan misalnya?

Jadi, segariskan persyaratan bisnis Anda untuk pendataan audit Anda. Cobalah untuk memprediksi bagaimana persyaratan ini dapat berubah di masa depan dan hasilkan persyaratan teknis Anda. Sekarang Anda dapat membandingkannya dengan pro dan kontra dan memilih opsi yang tepat / terbaik.

Dan yakinlah, tidak masalah bagaimana Anda memutuskan, akan selalu ada seseorang yang berpikir Anda membuat keputusan yang salah. Namun, Anda melakukan pekerjaan rumah Anda dan Anda membenarkan keputusan Anda.

Peter Schuetze
sumber