Đây là một cách đơn giản để thực hiện việc này:
Đầu tiên, hãy tạo một bảng lịch sử cho mỗi bảng dữ liệu bạn muốn theo dõi (truy vấn ví dụ bên dưới). Bảng này sẽ có một mục nhập cho mỗi truy vấn chèn, cập nhật và xóa được thực hiện trên mỗi hàng trong bảng dữ liệu.
Cấu trúc của bảng lịch sử sẽ giống như bảng dữ liệu mà nó theo dõi ngoại trừ ba cột bổ sung:một cột để lưu trữ thao tác đã xảy ra (chúng ta hãy gọi nó là 'hành động'), ngày và giờ của thao tác và một cột để lưu trữ một số thứ tự ('bản sửa đổi'), số này tăng lên mỗi thao tác và được nhóm theo cột khóa chính của bảng dữ liệu.
Để thực hiện hành vi trình tự này, một chỉ mục hai cột (tổng hợp) được tạo trên cột khóa chính và cột sửa đổi. Lưu ý rằng bạn chỉ có thể thực hiện trình tự theo cách này nếu công cụ được sử dụng bởi bảng lịch sử là MyISAM (Xem 'Ghi chú MyISAM' trên trang này)
Bảng lịch sử khá dễ tạo. Trong truy vấn ALTER TABLE bên dưới (và trong các truy vấn kích hoạt bên dưới), hãy thay thế 'primary_key_column' bằng tên thực của cột đó trong bảng dữ liệu của bạn.
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);
Và sau đó bạn tạo các trình kích hoạt:
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;
Và bạn đã hoàn thành. Bây giờ, tất cả các lần chèn, cập nhật và xóa trong 'MyDb.data' sẽ được ghi lại trong 'MyDb.data_history', cung cấp cho bạn một bảng lịch sử như thế này (trừ cột 'data_columns' được tạo sẵn)
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
Để hiển thị các thay đổi cho một cột nhất định hoặc các cột từ bản cập nhật đến bản cập nhật, bạn cần phải kết hợp bảng lịch sử với chính nó trên khóa chính và các cột trình tự. Bạn có thể tạo một dạng xem cho mục đích này, ví dụ:
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
Chỉnh sửa:Ồ wow, mọi người thích thứ bảng lịch sử của tôi từ 6 năm trước:P
Tôi cho rằng việc triển khai nó vẫn còn ì ạch, ngày càng lớn hơn và khó sử dụng hơn. Tôi đã viết các khung nhìn và giao diện người dùng khá đẹp để xem lịch sử trong cơ sở dữ liệu này, nhưng tôi không nghĩ rằng nó đã từng được sử dụng nhiều. Vậy là xong.
Để giải quyết một số nhận xét không theo thứ tự cụ thể:
-
Tôi đã thực hiện triển khai của riêng mình trong PHP, có liên quan nhiều hơn một chút và tránh được một số vấn đề được mô tả trong nhận xét (đáng kể là có các chỉ mục được chuyển qua. Nếu bạn chuyển các chỉ mục duy nhất sang bảng lịch sử, mọi thứ sẽ bị hỏng. Có các giải pháp cho này trong phần bình luận). Theo dõi bài đăng này đến bức thư có thể là một cuộc phiêu lưu, tùy thuộc vào cách thiết lập cơ sở dữ liệu của bạn.
-
Nếu mối quan hệ giữa khóa chính và cột sửa đổi dường như không có nghĩa là khóa tổng hợp bị khóa bằng cách nào đó. Trong một vài trường hợp hiếm hoi, tôi đã để xảy ra điều này và không biết rõ nguyên nhân.
-
Tôi nhận thấy giải pháp này khá hiệu quả, sử dụng các trình kích hoạt như nó vốn có. Ngoài ra, MyISAM chèn nhanh, đó là tất cả những gì mà trình kích hoạt làm. Bạn có thể cải thiện điều này hơn nữa với lập chỉ mục thông minh (hoặc thiếu ...). Chèn một hàng vào bảng MyISAM với khóa chính không phải là một thao tác bạn cần tối ưu hóa, thực sự, trừ khi bạn gặp sự cố nghiêm trọng đang xảy ra ở nơi khác. Trong toàn bộ thời gian tôi đang chạy cơ sở dữ liệu MySQL, việc triển khai bảng lịch sử này đã được bật, nó không bao giờ là nguyên nhân của bất kỳ (nhiều) sự cố hiệu suất nào xuất hiện.
-
nếu bạn bị chèn nhiều lần, hãy kiểm tra lớp phần mềm của bạn để biết loại CHÈN BỎ truy vấn. Hrmm, không thể nhớ bây giờ, nhưng tôi nghĩ có vấn đề với lược đồ này và các giao dịch cuối cùng không thành công sau khi chạy nhiều hành động DML. Ít nhất cũng cần phải lưu ý điều gì đó.
-
Điều quan trọng là các trường trong bảng lịch sử và bảng dữ liệu phải khớp với nhau. Hay nói đúng hơn là bảng dữ liệu của bạn không có NHIỀU cột hơn bảng lịch sử. Nếu không, các truy vấn chèn / cập nhật / del trên bảng dữ liệu sẽ không thành công, khi các lần chèn vào bảng lịch sử đặt các cột trong truy vấn không tồn tại (do d. * Trong truy vấn trình kích hoạt) và trình kích hoạt không thành công. Sẽ thật tuyệt nếu MySQL có thứ gì đó giống như các trình kích hoạt giản đồ, nơi bạn có thể thay đổi bảng lịch sử nếu các cột được thêm vào bảng dữ liệu. MySQL có cái đó bây giờ không? Tôi làm React những ngày này:P