Mysql
 sql >> Teknologi Basis Data >  >> RDS >> Mysql

Apakah ada opsi/fitur MySQL untuk melacak riwayat perubahan pada catatan?

Berikut cara mudah untuk melakukannya:

Pertama, buat tabel riwayat untuk setiap tabel data yang ingin Anda lacak (contoh kueri di bawah). Tabel ini akan memiliki entri untuk setiap kueri penyisipan, pembaruan, dan penghapusan yang dilakukan pada setiap baris dalam tabel data.

Struktur tabel histori akan sama dengan tabel data yang dilacaknya kecuali tiga kolom tambahan:kolom untuk menyimpan operasi yang terjadi (sebut saja 'aksi'), tanggal dan waktu operasi, dan kolom untuk menyimpan nomor urut ('revisi'), yang bertambah per operasi dan dikelompokkan menurut kolom kunci utama dari tabel data.

Untuk melakukan perilaku pengurutan ini, indeks dua kolom (komposit) dibuat pada kolom kunci utama dan kolom revisi. Perhatikan bahwa Anda hanya dapat melakukan pengurutan dengan cara ini jika mesin yang digunakan oleh tabel riwayat adalah MyISAM (Lihat 'Catatan MyISAM' di halaman ini)

Tabel riwayat cukup mudah dibuat. Dalam kueri ALTER TABLE di bawah ini (dan dalam kueri pemicu di bawahnya), ganti 'primary_key_column' dengan nama sebenarnya dari kolom tersebut di tabel data Anda.

CREATE TABLE MyDB.data_history LIKE MyDB.data;

ALTER TABLE MyDB.data_history MODIFY COLUMN primary_key_column int(11) NOT NULL, 
   DROP PRIMARY KEY, ENGINE = MyISAM, ADD action VARCHAR(8) DEFAULT 'insert' FIRST, 
   ADD revision INT(6) NOT NULL AUTO_INCREMENT AFTER action,
   ADD dt_datetime DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER revision,
   ADD PRIMARY KEY (primary_key_column, revision);

Dan kemudian Anda membuat pemicunya:

DROP TRIGGER IF EXISTS MyDB.data__ai;
DROP TRIGGER IF EXISTS MyDB.data__au;
DROP TRIGGER IF EXISTS MyDB.data__bd;

CREATE TRIGGER MyDB.data__ai AFTER INSERT ON MyDB.data FOR EACH ROW
    INSERT INTO MyDB.data_history SELECT 'insert', NULL, NOW(), d.* 
    FROM MyDB.data AS d WHERE d.primary_key_column = NEW.primary_key_column;

CREATE TRIGGER MyDB.data__au AFTER UPDATE ON MyDB.data FOR EACH ROW
    INSERT INTO MyDB.data_history SELECT 'update', NULL, NOW(), d.*
    FROM MyDB.data AS d WHERE d.primary_key_column = NEW.primary_key_column;

CREATE TRIGGER MyDB.data__bd BEFORE DELETE ON MyDB.data FOR EACH ROW
    INSERT INTO MyDB.data_history SELECT 'delete', NULL, NOW(), d.* 
    FROM MyDB.data AS d WHERE d.primary_key_column = OLD.primary_key_column;

Dan Anda sudah selesai. Sekarang, semua sisipan, pembaruan, dan penghapusan di 'MyDb.data' akan disimpan di 'MyDb.data_history', memberi Anda tabel riwayat seperti ini (dikurangi kolom 'data_columns' yang dibuat-buat)

ID    revision   action    data columns..
1     1         'insert'   ....          initial entry for row where ID = 1
1     2         'update'   ....          changes made to row where ID = 1
2     1         'insert'   ....          initial entry, ID = 2
3     1         'insert'   ....          initial entry, ID = 3 
1     3         'update'   ....          more changes made to row where ID = 1
3     2         'update'   ....          changes made to row where ID = 3
2     2         'delete'   ....          deletion of row where ID = 2 

Untuk menampilkan perubahan untuk kolom atau kolom tertentu dari pembaruan ke pembaruan, Anda harus menggabungkan tabel riwayat ke dirinya sendiri pada kunci utama dan kolom urutan. Anda dapat membuat tampilan untuk tujuan ini, misalnya:

CREATE VIEW data_history_changes AS 
   SELECT t2.dt_datetime, t2.action, t1.primary_key_column as 'row id', 
   IF(t1.a_column = t2.a_column, t1.a_column, CONCAT(t1.a_column, " to ", t2.a_column)) as a_column
   FROM MyDB.data_history as t1 INNER join MyDB.data_history as t2 on t1.primary_key_column = t2.primary_key_column 
   WHERE (t1.revision = 1 AND t2.revision = 1) OR t2.revision = t1.revision+1
   ORDER BY t1.primary_key_column ASC, t2.revision ASC

Sunting:Oh wow, orang-orang menyukai tabel sejarah saya dari 6 tahun yang lalu :P

Implementasi saya masih bersenandung, semakin besar dan semakin berat, saya kira. Saya menulis tampilan dan UI yang cukup bagus untuk melihat riwayat di database ini, tetapi saya rasa itu tidak pernah banyak digunakan. Jadi begitulah.

Untuk mengatasi beberapa komentar tanpa urutan tertentu:

  • Saya melakukan implementasi saya sendiri di PHP yang sedikit lebih terlibat, dan menghindari beberapa masalah yang dijelaskan dalam komentar (memiliki indeks yang ditransfer, secara signifikan. Jika Anda mentransfer indeks unik ke tabel riwayat, semuanya akan rusak. Ada solusi untuk ini di komentar). Mengikuti posting ini hingga surat bisa menjadi petualangan, tergantung pada seberapa mapan database Anda.

  • Jika hubungan antara kunci utama dan kolom revisi tampak tidak aktif, biasanya itu berarti kunci komposit entah bagaimana rusak. Pada beberapa kesempatan langka saya mengalami ini dan tidak tahu penyebabnya.

  • Saya menemukan solusi ini cukup berkinerja, menggunakan pemicu seperti halnya. Juga, MyISAM cepat dalam menyisipkan, yang dilakukan oleh semua pemicu. Anda dapat meningkatkan ini lebih lanjut dengan pengindeksan cerdas (atau kurangnya ...). Memasukkan satu baris ke tabel MyISAM dengan kunci utama seharusnya bukan operasi yang perlu Anda optimalkan, sungguh, kecuali jika Anda memiliki masalah signifikan yang terjadi di tempat lain. Selama saya menjalankan database MySQL, implementasi tabel riwayat ini tidak pernah menjadi penyebab (banyak) masalah kinerja yang muncul.

  • jika Anda mendapatkan sisipan berulang, periksa lapisan perangkat lunak Anda untuk jenis kueri INSERT IGNORE. Hrmm, tidak ingat sekarang, tapi saya pikir ada masalah dengan skema ini dan transaksi yang akhirnya gagal setelah menjalankan beberapa tindakan DML. Sesuatu yang harus diperhatikan, setidaknya.

  • Sangat penting bahwa bidang dalam tabel riwayat dan tabel data cocok. Atau, lebih tepatnya, tabel data Anda tidak memiliki LEBIH BANYAK kolom daripada tabel riwayat. Jika tidak, kueri sisipkan/perbarui/del pada tabel data akan gagal, saat penyisipan ke tabel riwayat menempatkan kolom dalam kueri yang tidak ada (karena d.* dalam kueri pemicu), dan pemicu gagal. t akan luar biasa jika MySQL memiliki sesuatu seperti pemicu skema, di mana Anda dapat mengubah tabel riwayat jika kolom ditambahkan ke tabel data. Apakah MySQL memilikinya sekarang? Saya melakukan Bereaksi hari ini :P



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Cara memunculkan kesalahan dalam fungsi MySQL

  2. Alternatif pt-query-digest - Manajemen &Pemantauan Kueri MySQL dengan ClusterControl

  3. Cara Menggunakan Coalesce di MySQL

  4. Sintaks MySQL untuk Pembaruan Gabung

  5. SQL pilih hanya baris dengan nilai maksimal pada kolom