Berikut cara langsung untuk melakukan ini:
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 sejarah akan sama dengan tabel data yang dilacak kecuali tiga kolom tambahan: kolom untuk menyimpan operasi yang terjadi (sebut saja 'tindakan'), tanggal dan waktu operasi, dan kolom untuk menyimpan nomor urut ('revisi'), yang bertambah per operasi dan dikelompokkan berdasarkan 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. Di kueri ALTER TABLE di bawah (dan di kueri pemicu di bawahnya), ganti 'primary_key_column' dengan nama sebenarnya dari kolom itu 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 pemicu:
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 penyisipan, pembaruan, dan penghapusan di 'MyDb.data' akan disimpan di 'MyDb.data_history', memberi Anda tabel riwayat seperti ini (minus 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 pada kolom atau kolom tertentu dari pembaruan ke pembaruan, Anda harus menggabungkan tabel riwayat ke tabel itu 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 tentang hal itu masih terus berlanjut, menjadi lebih besar dan lebih berat, saya kira. Saya menulis tampilan dan UI yang cukup bagus untuk melihat sejarah dalam database ini, tapi saya rasa itu tidak pernah banyak digunakan. Begitu seterusnya.
Untuk menjawab 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 ditransfer, secara signifikan. Jika Anda mentransfer indeks unik ke tabel riwayat, semuanya akan rusak. Ada solusi untuk ini di komentar). Mengikuti posting ini ke surat itu bisa menjadi petualangan, tergantung pada seberapa mapan database Anda.
Jika hubungan antara kunci utama dan kolom revisi tampak tidak aktif, biasanya kunci komposit mengalami gangguan. Pada beberapa kesempatan langka, saya mengalami hal ini dan kehilangan tujuan.
Saya menemukan solusi ini cukup berkinerja, menggunakan pemicu seperti itu. Juga, MyISAM cepat dalam menyisipkan, yang dilakukan oleh semua pemicu. Anda dapat meningkatkan ini lebih jauh dengan pengindeksan cerdas (atau kurangnya ...). Memasukkan satu baris ke dalam tabel MyISAM dengan kunci utama seharusnya tidak menjadi operasi yang perlu Anda optimalkan, sungguh, kecuali Anda memiliki masalah signifikan yang terjadi di tempat lain. Selama saya menjalankan database MySQL, implementasi tabel riwayat ini, tidak pernah menjadi penyebab dari (banyak) masalah performa yang muncul.
jika Anda mendapatkan penyisipan berulang, periksa lapisan perangkat lunak Anda untuk INSERT IGNORE jenis kueri. Hrmm, tidak dapat mengingatnya sekarang, tetapi saya pikir ada masalah dengan skema dan transaksi ini yang akhirnya gagal setelah menjalankan beberapa tindakan DML. Sesuatu yang harus diperhatikan, setidaknya.
Bidang di tabel riwayat dan tabel data harus cocok. Atau, 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 meletakkan kolom dalam kueri yang tidak ada (karena d. * Dalam kueri pemicu), dan pemicu gagal. Ini akan menjadi 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 React hari ini: P