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

Съхранявайте всички промени в данните с всички подробности (като Stackoverflow)

От известно време си мисля за това и мога да измисля само два начина да го направя. И двете могат да работят напълно прозрачно, когато са създадени в абстрактен слой/модел с данни.

Между другото, в доктрината за картографиране на ORM има реализация за "версионни" данни от таблици. Вижте този пример в техните документи . Може би това отговаря на вашите нужди, но не отговаря на моите. Изглежда, че изтрива всички данни от историята, когато оригиналният запис бъде изтрит, което го прави наистина небезопасен за ревизия.

Опция А:да имате копие на всяка таблица, за да съхранявате данни за ревизии

Да приемем, че имате проста таблица за контакти:

CREATE TABLE contact (
    id INT NOT NULL auto_increment,
    name VARCHAR(255),
    firstname VARCHAR(255),
    lastname VARCHAR(255),
    PRIMARY KEY (id)
)

Вие ще създадете копие на тази таблица и ще добавите ревизионни данни:

CREATE TABLE contact_revisions (
    id INT NOT NULL,
    name VARCHAR(255),
    firstname VARCHAR(255),
    lastname VARCHAR(255),
    revision_id INT auto_increment,
    type ENUM('INSERT', 'UPDATE', 'DELETE') NOT NULL,
    change_time DEFAULT current_timestamp,
    PRIMARY KEY(revision_id)
)

Следете INSERT и UPDATE с помощта на AFTER тригери. При всяка нова ревизия на данните в оригинала вмъкнете копие на новите данни в таблицата с ревизии и задайте модификацията type правилно.

За да влезете в DELETE безопасно при преразглеждане, трябва също да вмъкнете нов ред в таблицата на историята! За това трябва да използвате BEFORE DELETE задейства и съхранява най-новите стойности, преди да бъдат изтрити. В противен случай ще трябва да премахнете всеки NOT NULL ограничение и в таблицата на историята.

Някои важни бележки относно това внедряване

  • За таблицата на историята трябва да махнете всеки UNIQUE KEY (тук:PRIMARY KEY ) от таблицата с ревизии, защото ще имате един и същ ключ няколко пъти за всяка ревизия на данните.
  • Когато ALTER схемата и данните в оригиналната таблица чрез актуализация (например актуализация на софтуера) трябва да гарантирате, че същите данни или корекции на схемата се прилагат и към таблицата с история и нейните данни. В противен случай ще срещнете проблеми, когато се върнете към по-стара ревизия на набор от записи.
  • В реална реализация бихте искали да знаете кой потребител е променил данните. За да има тази ревизионна безопасност, потребителският запис никога не трябва да се изтрива от таблицата с потребители. Трябва просто да деактивирате акаунта с флаг.
  • Обикновено едно действие на потребителя включва повече от една таблица. В реална реализация ще трябва също да следите кои промени в множество таблици принадлежат на една транзакция на един потребител и също в кой ред. В реален случай на използване бихте искали да отмените всички промени на една транзакция заедно, в обратен ред. Това ще изисква допълнителна таблица с ревизии, която следи потребителите и транзакциите и поддържа свободна връзка с всички тези отделни ревизии в таблиците на историята.

Предимства:

  • напълно в база данни, независимо от кода на приложението. (е, не, когато проследяването на потребителските транзакции е важно. това ще изисква известна логика извън обхвата на единичната заявка)
  • всички данни са в оригиналния им формат, без неявни преобразувания на тип.
  • добро представяне при търсене в ревизиите
  • лесно връщане назад. Просто направете просто INSERT .. ON DUPLICATE KEY UPDATE .. изявление в оригиналната таблица, използвайки данните от ревизията, която искате да върнете назад.

Заслуги:

  • Трудно е за внедряване ръчно.
  • Трудно (но не невъзможно) за автоматизиране, когато става въпрос за миграции на база данни/актуализации на приложения.

Както вече беше посочено по-горе, доктрини versionable прави нещо подобно.

Вариант Б:има централна таблица на дневника на промените

предговор:лоша практика, показана само за илюстрация на алтернативата.

Този подход до голяма степен разчита на логиката на приложението, която трябва да бъде скрита в слой данни/модел.

Имате централна хронология, която следи

  • Кой го направи
  • кога
  • променете, вмъкнете или изтрийте
  • какви данни
  • в кое поле
  • от коя таблица

Подобно на другия подход, може също да искате да проследите кои отделни промени в данните принадлежат на едно действие/транзакция на потребител и в кой ред.

Предимства:

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

Заслуги:

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

Заключение:

  • Опция Б може да бъде много удобен за малки приложения като прост "влизане", когато е само за регистриране на промени.
  • Ако искате да се върнете назад във времето и да можете лесно да сравнявате разликите между историческата ревизия 123 до ревизия 125 и/или върнете към старите данни, след което Опция A е трудният път.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. GROUP_CONCAT еквивалент в Django

  2. ScaleGrid DBaaS разширява MySQL хостинг услугите чрез AWS Cloud

  3. Таблицата е посочена два пъти, и като цел за 'UPDATE' и като отделен източник за данни в mysql

  4. Елиминирайте подзаявката за средна числова стойност

  5. Безопасна ли е нишката за свързване на pymysql? Безопасна ли е нишката на курсора на pymysql?