Лучший дизайн для таблицы базы данных журнала изменений / аудита? [закрыто]

114

Мне нужно создать таблицу базы данных для хранения различных журналов изменений / аудита (когда что-то было добавлено, удалено, изменено и т. Д.). Мне не нужно хранить особенно подробную информацию, поэтому я подумал что-то вроде:

  • id (для события)
  • пользователь, который вызвал это
  • название события
  • Описание события
  • отметка времени события

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

rcphq
источник
Я прочитал твой ответ и удивлен, что никто не говорит о Ло. Я знаю, что в некоторых законах или хороших практических документах объясняется, как мы ДОЛЖНЫ реализовать (только для чтения) таблицу аудита. Но у меня нет дополнительной информации, кроме этой. Я просто знаю, что он существует. Я думаю об аудиторском следе в Свода федеральных правил 21, часть 11.
Бастьен Вандамм
12
Может быть полезно: ludwigstuyck.wordpress.com/2013/04/04/history-tracking
L-Four

Ответы:

70

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

event ID
event date/time
event type
user ID
description

Идея была та же: все было просто.

Однако быстро стало очевидно, что этого минималистичного дизайна недостаточно. Типичный аудит сводился к следующим вопросам:

Who the heck created/updated/deleted a record 
with ID=X in the table Foo and when?

Итак, чтобы иметь возможность быстро отвечать на такие вопросы (с помощью SQL), мы получили два дополнительных столбца в таблице аудита.

object type (or table name)
object ID

Именно тогда дизайн нашего журнала аудита действительно стабилизировался (вот уже несколько лет).

Конечно, последнее «улучшение» будет работать только для таблиц с суррогатными ключами. Но знаете что? Все наши таблицы, которые стоит проверить, имеют такой ключ!

Ярик
источник
Единственная проблема, с которой я столкнулся с этим дизайном (контрольный журнал на основе «описания»), - это локализация языка, используемого в этой области.
Сэм Уилсон
@Sam Я не вижу такой проблемы, если сообщение сгенерировано системой, просто используйте здесь ключ для строки перевода;
JCM
4
@Hiru: Когда вы "смешиваете" две или более различных концепции в один столбец, чаще всего рано или поздно это дает обратный эффект. Например, если вы «смешиваете» тип события и тип объекта, это повлияет на такие запросы, как «показать мне записи для всех объектов данного типа» и «показать мне записи для всех событий данного типа» (запросы будут больше сложный и, скорее всего, будет работать намного медленнее).
Ярик
3
В дополнение к этим столбцам можно иметь дополнительный столбец для структурированного описания / полезной нагрузки структурированного события . Этот столбец будет содержать сведения о событиях (любой сложности) в машиночитаемом формате XML / JSON. Легко сериализовать, запросить (по крайней мере, в Postgres / MSSQL), рассуждать о.
turdus-merula
1
@Benjamin: Ответ кроется в модели предметной области (или бизнес-модели). Если модель позволяет одновременное создание сущностей (например, как часть логической транзакции), то я не вижу никаких проблем в наличии нескольких записей журнала с точно такой же меткой времени. Например, если создание заказа на поставку (как транзакция) может включать создание N позиций заказа, то все соответствующие записи журнала 1 + N будут иметь одинаковую временную метку. Последующий анализ такого журнала может воспользоваться этим, рассматривая эти записи 1 + N не как независимые, а как элементы логической транзакции. Надеюсь, это имеет смысл.
Ярик
24

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

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

HLGEM
источник
1
Это действительно хорошо, я не понимаю, почему люди игнорируют последние сообщения.
Maddy.Shik
3
Источники событий - это альтернативный подход к предоставлению возможности отката с сохранением истории.
Сэм
23

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

Теперь это зависит от того, насколько подробный аудит вам действительно нужен и на каком уровне.

Мы начали создавать собственное решение для аудита на основе триггеров, и мы хотели проверять все, а также иметь возможность восстановления под рукой. Это оказалось слишком сложно, поэтому мы закончили реверс-инжиниринг стороннего инструмента ApexSQL Audit на основе триггеров, чтобы создать собственное решение.

Подсказки:

  • Включить значения до и после

  • Включите 3-4 столбца для хранения первичного ключа (если это составной ключ)

  • Хранить данные вне основной базы данных, как уже предложил Роберт

  • Потратьте приличное количество времени на подготовку отчетов - особенно тех, которые могут понадобиться для восстановления

  • Планирование хранения имени хоста / приложения - это может быть очень полезно для отслеживания подозрительных действий.

Кеннет Хэмптон
источник
2
Зачем вам перепроектировать его вместо того, чтобы покупать?
Jowen
1
больше контроля над продуктом
Тебе
1
Надеюсь, они не подали на тебя в суд.
Sorter
9

Здесь и на подобные вопросы много интересных ответов. Единственное, что я могу добавить из личного опыта:

  1. Поместите свою таблицу аудита в другую базу данных. В идеале вы хотите отделиться от исходных данных. Если вам нужно восстановить базу данных, вы действительно не хотите восстанавливать журнал аудита.

  2. Денормализуйте насколько это возможно. Вы хотите, чтобы таблица имела как можно меньше зависимостей от исходных данных. Таблица аудита должна быть простой и молниеносной для извлечения данных. Никаких причудливых объединений или поисков в других таблицах для доступа к данным.

Robert4Real
источник
8
Действительно ли ненормализованные данные будут считываться быстрее, чем нормализованные данные с соответствующими индексами? (Разве все дублирование не приведет к чтению большего количества данных с жесткого диска?)
Сэм
4

Что у нас в таблице: -

Primary Key
Event type (e.g. "UPDATED", "APPROVED")
Description ("Frisbar was added to blong")
User Id
User Id of second authoriser
Amount
Date/time
Generic Id
Table Name

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

WW.
источник
2
Что означает «сумма»?
turdus-merula
Это финансовое приложение, значит, это долларовая стоимость авторизуемого объекта и т. Д.
WW.
4

В целом кастомный аудит (создание различных таблиц) - плохой вариант. Триггеры базы данных / таблицы можно отключить, чтобы пропустить некоторые действия журнала. Настраиваемые таблицы аудита могут быть изменены. Могут иметь место исключения, которые приведут к остановке приложения. Не упоминать о трудностях разработки надежного решения. Пока я вижу в этом обсуждении очень простые случаи. Вам необходимо полное отделение от текущей базы данных и от любых привилегированных пользователей (администраторов баз данных, разработчиков). Каждая распространенная СУБД предоставляет средства аудита, которые даже администратор баз данных не может отключить, нарушая конфиденциальность. Следовательно, возможность аудита, предоставляемая поставщиком РСУБД, должна быть первым вариантом. Другим вариантом может быть стороннее средство чтения журнала транзакций или пользовательское средство чтения журнала, которое отправляет разложенную информацию в систему обмена сообщениями, которая в конечном итоге оказывается в некоторых формах хранилища данных аудита или обработчика событий в реальном времени. В итоге: Архитектор решений / «Практикующий архитектор данных» должен участвовать в создании такой системы на основе требований. Обычно это слишком серьезные вещи, чтобы просто передать их разработчикам для решения.

Джоэл Мамедов
источник
3

Есть много способов сделать это. Мой любимый способ:

  1. Добавьте mod_userполе в исходную таблицу (то, которое вы хотите зарегистрировать).

  2. Создание таблицы журнала , который содержит поле , которые вы хотите , чтобы войти, плюс log_datetimeи seq_numполе. seq_numэто первичный ключ.

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

Теперь у вас есть записи обо всех изменениях и о том, кто их сделал.

JosephStyons
источник
Итак ... что должно делать поле mod_user?
conny
1
Скажите, кто внес изменения. Код обновления должен включать что-то, чтобы установить это поле для текущего пользователя.
JosephStyons
А как насчет удалений? Если вы удалите строку, как вы обработаете значение столбца mod_user?
Kenn Cal
Триггеры @KennCal могут использовать виртуальные таблицы, вы можете видеть данные после и до внутри одного и того же триггера. Не имеет значения операция. stackoverflow.com/questions/6282618/…
Renan Cavalieri
2
@KennCal Вы правы, триггер удаления должен либо сохранить эту информацию для вас. Однако дьявол кроется в деталях - если вы используете аутентификацию SQL, триггер может просто запустить [выберите CURRENT_USER]. Если это клиентское приложение, то клиентский код должен сообщить, кто это. Если это вызов API, то удаляющий пользователь должен быть обязательным параметром для вызова.
JosephStyons
1

По принципу разделения:

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

  2. Не используйте триггеры для аудита всей базы данных, потому что вам придется поддерживать множество разных баз данных. Вам нужно будет написать один для DB2, SQLServer, Mysql и т. Д.

Bhagat007
источник