Как обычно хранится запись каждого изменения строки в базе данных?

10

В проекте, над которым я работаю, каждое изменение строк в некоторых таблицах базы данных должно отслеживаться для дальнейшего аудита или отката. Должно быть легко найти, кто изменил строку, с какого IP-адреса и когда, и иметь возможность восстановить предыдущую версию.

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

Какой общий метод используется для хранения каждого изменения объекта в базе данных , учитывая, что моя текущая схема имеет в основном те же свойства (ниже), что и обычное бизнес-приложение?

  • Объекты имеют относительно небольшой размер: это могут быть, nvarchar(1000)например, некоторые , но не огромные двоичные объекты двоичных данных, которые хранятся непосредственно на диске и доступны напрямую, а не через Microsoft SQL filestream,
  • Загрузка базы данных довольно низкая, и вся база данных обрабатывается одной виртуальной машиной на сервере,
  • Доступ к предыдущим версиям не должен быть таким же быстрым, как доступ к последней версии, но все же должен быть актуальным и не слишком медленным2.

<ТЛ-дг>

Я думал о следующих случаях, но у меня нет никакого реального опыта с такими сценариями, поэтому я услышал бы мнения других:

  1. Сохраните все в одной таблице, различая строки по идентификатору и версии. ИМО, это серьезно глупо и рано или поздно повредит уровню производительности. При таком подходе также невозможно установить другой уровень безопасности для последних элементов и трассировки версий. Наконец, каждый запрос будет сложнее написать. На самом деле, чтобы получить доступ к актуальным данным, я был бы вынужден сгруппировать все по идентификатору и получить в каждой группе последнюю версию.

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

  3. Сохраните последнюю версию в одной таблице, а список измененных свойств с их предыдущими значениями - в другой таблице. Кажется, у этого есть два недостатка: самый важный из них заключается в том, что единственный способ сортировки разнородных типов предыдущих значений в одном столбце - это иметь binary(max). Во-вторых, я полагаю, что было бы сложнее использовать такую ​​структуру при отображении предыдущих версий пользователю.

  4. Сделайте то же самое, что и в двух предыдущих пунктах, но сохраните версии в отдельной базе данных. С точки зрения производительности, это может быть интересно, чтобы избежать замедления доступа к последним версиям, если предыдущие версии находятся в той же базе данных; тем не менее, я считаю, что это преждевременная оптимизация, и ее следует проводить только в том случае, если есть доказательство того, что наличие более старых и последних версий в одной и той же базе данных является узким местом.

</ ТЛ-дг>


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

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

Арсений Мурзенко
источник
3
Соответствующий: сбор данных изменения SQL Server .
Ник Чаммас

Ответы:

8

Обычный способ ведения журнала аудита такого рода состоит в том, чтобы иметь теневую таблицу и регистрировать изменения с помощью триггеров на базовой таблице, которую вы проверяете. Другие таблицы могут быть размещены на другом физическом диске, если вам это необходимо для повышения производительности, и вы можете размещать на них индексы, если вам необходимо поддерживать быстрый поиск данных.

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

Изменить дату можно, установив для столбца datetime значение NULL со значением по умолчанию getdate (); пользовательский столбец аудита будет захватывать пользователя с ненулевым столбцом по умолчанию Suser_Sname (). Если предположить, что в сеансе выдают себя за действительного пользователя, это будет идентифицировать личность пользователя, вносящего изменения.

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

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

Это решение, безусловно, является лучшим по нескольким причинам:

  • Он фиксирует любые изменения в таблице, а не только те, которые внесены приложением.

  • Таблицы аудита могут быть помещены на другой набор дисков, чтобы уменьшить нагрузку ввода-вывода на ваши основные таблицы.

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

  • При необходимости вы можете индексировать таблицы журнала аудита, чтобы пользователи аудита могли отвечать на них быстро. Как обычно, выбор индекса - это компромисс между производительностью запросов и издержками на обновление.

ConcernedOfTunbridgeWells
источник
Вы пытаетесь сказать, если у меня есть 1000 таблиц, которые мне нужно вести журнал для любых изменений, то я должен создать 1000 теневых таблиц да? а 1000 триггер для захвата изменений? если да, то это ложная идея ... мы можем создать единую таблицу истории и один триггер для сбора и регистрации измененных данных. мы можем хранить старые и новые данные строк в этой таблице в формате xml .... это делают многие люди ... понятно?
Томас
1
Для 1000 таблиц вы пишете utlity, который читает определения из словаря системных данных и генерирует триггеры и определения таблиц. Я сделал это в системе с 560 таблицами, и она прекрасно работает.
ConcernedOfTunbridgeWells
0

Я знаю о многих системах CMS (включая Wordpress), которые используют одну таблицу для хранения всех версий данных. Но опять же, они должны сделать это только для таблицы, в которой есть сообщения в блоге. Смотрите структуру базы данных Wordpress .

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

Дхармендар Кумар 'DK'
источник
0

О версии CMS; для drupal он создает специальную таблицу для каждого поля сущности, в которой хранится старое значение; такая концепция позволяет вам аккуратно манипулировать вашими данными, но я думаю, что это дорого, мое собственное решение состоит в том, чтобы преобразовать мой объект в формат xml и сохранить его в виде строки с другими полями (changetime, id ...)

Bourkadi
источник