Mysql
 sql >> база данни >  >> RDS >> Mysql

Има ли MySQL опция/функция за проследяване на историята на промените в записи?

Ето един лесен начин да направите това:

Първо, създайте таблица с история за всяка таблица с данни, която искате да проследявате (примерна заявка по-долу). Тази таблица ще има запис за всяка заявка за вмъкване, актуализиране и изтриване, извършена на всеки ред в таблицата с данни.

Структурата на таблицата с хронологията ще бъде същата като таблицата с данни, която проследява, с изключение на три допълнителни колони:колона за съхраняване на извършената операция (нека я наречем „действие“), датата и часа на операцията и колона за съхраняване на пореден номер („ревизия“), който се увеличава на операция и е групиран от колоната с първичен ключ на таблицата с данни.

За да направите това поведение на последователност, се създава индекс с две колони (композитен) в колоната с първичен ключ и колоната за ревизия. Имайте предвид, че можете да правите секвениране по този начин само ако двигателят, използван от таблицата с история, е MyISAM (Вижте „Бележки по MyISAM“ на тази страница)

Таблицата на историята е сравнително лесна за създаване. В заявката ALTER TABLE по-долу (и в задействащите заявки под нея) заменете „primary_key_column“ с действителното име на тази колона във вашата таблица с данни.

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);

След това създавате тригерите:

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;

И сте готови. Сега всички вмъквания, актуализации и изтривания в 'MyDb.data' ще бъдат записани в 'MyDb.data_history', давайки ви таблица с историята като тази (минус измислената колона 'data_columns')

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 

За да покажете промените за дадена колона или колони от актуализация до актуализация, ще трябва да присъедините хронологията към себе си в колоните с първичен ключ и последователност. Можете да създадете изглед за тази цел, например:

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

Редактиране:О, уау, хората харесват моята история от преди 6 години :P

Моето изпълнение все още си тананика, става все по-голямо и по-трудно, бих предположил. Написах изгледи и доста приятен потребителски интерфейс, за да разгледам историята в тази база данни, но не мисля, че някога е била използвана много. Така става.

За да адресирате някои коментари в определен ред:

  • Направих собствена реализация в PHP, която беше малко по-ангажирана и избегнах някои от проблемите, описани в коментарите (прехвърлянето на индекси значително. Ако прехвърлите уникални индекси в таблицата с историята, нещата ще се счупят. Има решения за това в коментарите). Следването на тази публикация до писмото може да бъде приключение, в зависимост от това колко е установена вашата база данни.

  • Ако връзката между първичния ключ и колоната за ревизия изглежда изключена, това обикновено означава, че съставният ключ е блокиран по някакъв начин. В няколко редки случая ми се е случвало това и съм бил в загуба на каузата.

  • Открих, че това решение е доста ефективно, използвайки тригери, както го прави. Също така MyISAM е бърз при вмъкване, което е всичко, което правят тригерите. Можете да подобрите това допълнително с интелигентно индексиране (или липса на...). Вмъкването на един ред в таблица MyISAM с първичен ключ не трябва да е операция, която трябва да оптимизирате, наистина, освен ако нямате значителни проблеми, които се случват другаде. През цялото време, когато изпълнявах базата данни MySQL, тази имплементация на хронологията на таблицата беше включена, тя никога не беше причина за някой от (многото) проблеми с производителността, които се появиха.

  • ако получавате повтарящи се вмъквания, проверете вашия софтуерен слой за заявки от тип INSERT IGNORE. Хм, не мога да си спомня сега, но мисля, че има проблеми с тази схема и транзакции, които в крайна сметка се провалят след изпълнение на множество DML действия. Поне нещо, което трябва да знаете.

  • Важно е полетата в таблицата на историята и таблицата с данни да съвпадат. Или по-скоро, че вашата таблица с данни няма ПОВЕЧЕ колони от таблицата с история. В противен случай заявките за вмъкване/актуализация/дел в таблицата с данни ще се провалят, когато вмъкванията към таблиците с история поставят колони в заявката, които не съществуват (поради d.* в заявките за задействане), и тригерът се провали. Би било страхотно, ако MySQL имаше нещо като schema-triggers, където бихте могли да промените таблицата на историята, ако колоните се добавят към таблицата с данни. MySQL има ли това сега? Аз реагирам тези дни :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. Използване на разширени функции на Oracle JDeveloper за MySQL бази данни

  2. Как да получите размера на mysql базата данни?

  3. PDO обвързващи стойности за MySQL IN израз

  4. Сравнете датите в MySQL

  5. разделяне на ключови думи за post php mysql