Як зберігається запис кожної зміни рядка в базі даних?


10

У проекті, над яким я працюю, кожна зміна рядків у деяких таблицях бази даних повинна відслідковуватися для подальшого аудиту чи відката. Потрібно легко знайти, хто змінив рядок, з якої IP-адреси та коли, і зможе відновити попередню версію.

Аналогічну річ використовує, наприклад, Stack Exchange. Коли я змінюю чуже запитання, можна виявити, що я його змінив, і відкатати зміни.

Який загальний прийом використовується для зберігання кожної зміни об'єкта в базі даних , враховуючи, що моя поточна схема має в основному ті ж властивості (нижче), що і середній бізнес-додаток?

  • Об'єкти мають відносно невеликий розмір: можуть бути, nvarchar(1000)наприклад, деякі , але не величезні крапки двійкових даних, які зберігаються безпосередньо на диску, і доступ до них безпосередньо, а не через Microsoft SQL filestream,
  • Завантаження бази даних є досить низькою, і вся база даних обробляється однією віртуальною машиною на сервері,
  • Доступ до попередніх версій не повинен бути таким швидким, як доступ до останньої версії, але все ж повинен бути сучасним¹ і не надто повільним².

<tl-dr>

Я думав про наступні випадки, але у мене немає реального досвіду подібних сценаріїв, тому я почув би думку інших:

  1. Зберігайте все в одній таблиці, розрізняючи рядки за ідентифікацією та версією. IMO, це серйозно нерозумно, і рано чи пізно зашкодить на рівні продуктивності. При такому підході також неможливо встановити інший рівень безпеки для останніх позицій та для відстеження версій. Нарешті, кожен запит було б складніше написати. Насправді, щоб отримати доступ до сучасних даних, я змушений був би згрупувати все за ідентифікатором та отримати в кожній групі останню версію.

  2. Зберігайте останню версію в одній таблиці та при кожному зміні скопіюйте застарілу версію в іншу таблицю в іншій схемі. Недолік у тому, що кожного разу ми зберігаємо кожне значення, навіть якщо воно не змінювалося. Встановлення незмінних значень nullне є рішенням, оскільки я також повинен відстежувати, коли значення змінюється на nullабо з нього null.

  3. Зберігайте останню версію в одній таблиці, а список змінених властивостей із попередніми значеннями - в іншій таблиці. Здається, є два недоліки: найважливішим є те, що єдиний спосіб сортування неоднорідних типів попередніх значень в одному стовпчику - це мати a binary(max). Другий - це, я вважаю, було б складніше використовувати таку структуру під час показу попередніх версій користувачеві.

  4. Зробіть те саме, що і в двох попередніх пунктах, але зберігайте версії в окремій базі даних. З точки зору продуктивності, це може бути цікавим, щоб уникнути уповільнення доступу до останніх версій, якщо попередні версії були в тій самій базі даних; все-таки я вважаю, що це передчасна оптимізація, і її потрібно робити лише за наявності доказів того, що наявність старих і останніх версій в одній базі даних є вузьким місцем.

</tl-dr>


¹ Наприклад, було б неприпустимо зберігати зміни у файлі журналу, як це робиться для HTTP-журналів, і передавати дані з журналу в базу даних вночі, коли завантаження сервера найменше. Інформація про різні версії повинна бути доступною негайно або майже негайно; кілька секунд затримка прийнятна.

² До інформації не доступний дуже часто і лише певна група користувачів, але все-таки було б неприпустимо змушувати їх чекати 30 секунд, щоб список версій відобразився. Знову ж таки, кілька секунд затримка прийнятна.


3
Відповідно: Збір даних про зміну SQL Server .
Нік Чаммас

Відповіді:


8

Нормальний спосіб зробити такий журнал аудиту - це мати тіньову таблицю та зміни журналів із запусками на базовій таблиці, яку ви ревізуєте. Інші таблиці можна помістити на інший фізичний диск, якщо вам це потрібно для продуктивності, і ви можете поставити на них індекси, якщо вам потрібно підтримати швидке отримання даних.

Таблиці матимуть приблизно таку саму структуру, що і ваші початкові таблиці, але матимуть стовпчик часу дати, коли відбулася зміна, і маркер того, чи рядок було вставлено, змінено чи видалено. Послідовність версій можна здійснити за допомогою позначки часу.

Дату зміни можна зробити, зробивши стовпець datetime не нульовим, за замовчуванням getdate (); стовпець користувача аудиту буде захоплювати користувача з ненульовим стовпцем, дефолтом якого є Suser_Sname (). Якщо припустити, що в сеансі підробляється дійсний користувач, це зафіксує особу користувача, який вносить зміни.

База даних не може бути обізнана про IP-адресу, що підключається до веб-сервера. Додаток повинен буде явно захопити та записати IP-адресу за допомогою транзакції.

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

Це рішення на сьогодні найкраще з кількох причин:

  • Він фіксує будь-які зміни в таблиці, не тільки ті, які внесені додатком.

  • Таблиці аудиту можна поставити на інший набір дисків, щоб зменшити навантаження вводу / виводу на ваші основні таблиці.

  • Ви можете використовувати подання, засноване на об'єднанні таблиці та журналу журналу аудиту, в якому буде показана вся історія, включаючи поточну версію.

  • Ви можете проіндексувати таблиці журналів аудиту за необхідності, щоб користувачі аудиту могли запитувати їх у відповідь. Як завжди, вибір індексу - це компроміс між ефективністю запиту та накладними оновленнями.


ви намагаєтеся сказати, чи є у мене 1000 таблиць, які мені потрібно вести журнал для будь-яких змін, то мені доведеться створити 1000 тіньових таблиць, так? і 1000 тригерів для фіксації зміни? якщо так, то це хибна ідея ... ми можемо створити єдину таблицю історії та єдиний тригер для захоплення та реєстрації змінених даних. ми можемо зберігати старі та нові дані рядків у цій таблиці як XML .... це багато людей робить .... я зрозумів !!
Томас

1
Для 1000 таблиць ви пишете промови, які читають визначення зі словника системних даних та генерують тригери та визначення таблиць. Я робив це в системі з 560 таблицями, і вона працює чудово.
Занепокоєний

0

Мені відомо багато систем CMS (включаючи Wordpress), які використовують єдину таблицю для зберігання всіх версій даних. Але знову ж таки, вони повинні зробити це лише для таблиці, в якій розміщені повідомлення в блозі. Дивіться структуру бази даних Wordpress .

Крім того, кількість записів та кількість змін, через які проходить кожен ряд, будуть грати важливу роль у вашому рішенні.


0

Про версію CMS; для drupal він складає спеціальну таблицю для кожного поля сутності, що зберігає старе значення; така концепція дозволяє вам тонко маніпулювати вашими даними, але я думаю, що це дорого, моє власне рішення - перетворити мій об'єкт у формат XML і зберегти його як рядок з іншими полями (changetime, id ...)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.