sql >> Databáze >  >> RDS >> Mysql

Existuje možnost/funkce MySQL pro sledování historie změn záznamů?

Zde je jednoduchý způsob, jak to udělat:

Nejprve vytvořte tabulku historie pro každou datovou tabulku, kterou chcete sledovat (příkladový dotaz níže). Tato tabulka bude mít záznam pro každý dotaz vložení, aktualizace a odstranění provedený na každém řádku v tabulce dat.

Struktura tabulky historie bude stejná jako tabulka dat, kterou sleduje, kromě tří dalších sloupců:sloupec pro uložení operace, která se odehrála (říkejme tomu „akce“), datum a čas operace a sloupec k uložení pořadového čísla („revize“), které se zvyšuje podle operace a je seskupeno podle sloupce primárního klíče datové tabulky.

Za tímto účelem se ve sloupci primárního klíče a sloupci revize vytvoří dvousloupcový (složený) index. Upozorňujeme, že tímto způsobem můžete provádět sekvenování pouze v případě, že motor používaný tabulkou historie je MyISAM (Viz „Poznámky MyISAM“ na této stránce)

Vytvoření tabulky historie je poměrně snadné. V dotazu ALTER TABLE níže (a ve spouštěcích dotazech níže) nahraďte 'primary_key_column' skutečným názvem tohoto sloupce ve vaší datové tabulce.

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

A pak vytvoříte spouštěče:

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;

A máte hotovo. Nyní budou všechna vložení, aktualizace a smazání v 'MyDb.data' zaznamenána v 'MyDb.data_history', což vám poskytne tabulku historie, jako je tato (minus vytvořený sloupec '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 

Chcete-li zobrazit změny pro daný sloupec nebo sloupce od aktualizace po aktualizaci, budete muset propojit tabulku historie s primárním klíčem a sloupci sekvence. Pro tento účel můžete vytvořit pohled, například:

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

Edit:Oh wow, lidem se líbí moje věc s tabulkou historie před 6 lety :P

Moje implementace stále hučí, je stále větší a nemotornější, předpokládám. Napsal jsem pohledy a docela pěkné uživatelské rozhraní, abych se podíval na historii v této databázi, ale myslím, že se nikdy moc nepoužíval. Tak to jde.

Chcete-li reagovat na některé komentáře v žádném konkrétním pořadí:

  • Udělal jsem svou vlastní implementaci v PHP, která byla o něco složitější, a vyhnul jsem se některým problémům popsaným v komentářích (významně jsem přenesl indexy. Pokud přenesete jedinečné indexy do tabulky historie, věci se pokazí. Existují řešení pro toto v komentářích). Sledování tohoto příspěvku do písmene může být dobrodružství, v závislosti na tom, jak je vaše databáze zavedená.

  • Pokud se zdá, že vztah mezi primárním klíčem a sloupcem revize je vypnutý, obvykle to znamená, že složený klíč je nějak zarámovaný. Při několika vzácných příležitostech se mi to stalo a nevěděl jsem o příčině.

  • Zjistil jsem, že toto řešení je docela výkonné, protože používá spouštěče. MyISAM je také rychlý při vkládání, což je vše, co spouštěče dělají. Toto můžete dále vylepšit pomocí chytrého indexování (nebo nedostatku...). Vložení jednoho řádku do tabulky MyISAM s primárním klíčem by ve skutečnosti nemělo být operací, kterou byste museli optimalizovat, pokud nemáte jiné závažné problémy. Za celou dobu, co jsem provozoval databázi MySQL, tato implementace tabulky historie byla zapnutá, nikdy to nebylo příčinou žádného z (mnoha) problémů s výkonem, které se objevily.

  • pokud se vám vkládání opakuje, zkontrolujte ve své softwarové vrstvě dotazy typu INSERT IGNORE. Hrmm, teď si nemůžu vzpomenout, ale myslím, že s tímto schématem a transakcemi jsou problémy, které nakonec selžou po spuštění více akcí DML. Alespoň něco, o čem je třeba vědět.

  • Je důležité, aby se pole v tabulce historie a datové tabulce shodovala. Nebo spíše, že vaše datová tabulka nemá VÍCE sloupců než tabulka historie. Jinak dotazy typu insert/update/del na datovou tabulku selžou, když vložení do tabulek historie vloží do dotazu sloupce, které neexistují (kvůli d.* ve spouštěcích dotazech) a spouštěč selže. Bylo by úžasné, kdyby MySQL mělo něco jako spouštěče schémat, kde byste mohli změnit tabulku historie, pokud byly do tabulky dat přidány sloupce. Má to teď MySQL? V těchto dnech reaguji :P



  1. Ovladač Google BigQuery ODBC

  2. Instalace SQLite

  3. Jak spustit úlohu SQL Server Agent pomocí T-SQL

  4. Rozdíl mezi SYSDATE() a NOW() v MariaDB