Ведение журнала аудита для объектов, разделенных на несколько таблиц - PullRequest
3 голосов
/ 19 января 2009

У нас есть сущность, разделенная на 5 разных таблиц. Записи в 3 из этих таблиц являются обязательными. Записи в двух других таблицах являются необязательными (в зависимости от подтипа сущности).

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

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

Таким образом, текущие записи всегда находятся в живых таблицах, а история / изменения - в таблицах истории. Исторические записи можно упорядочить по столбцу меток времени. Очевидно, что столбцы меток времени не связаны между таблицами истории.

Теперь, для более сложной части.

  1. Записи изначально вставляются в одну транзакцию. В одну транзакцию будет записано 3 или 5 записей.
  2. Отдельные обновления могут происходить с любой или всеми 5 таблицами.
  3. Все записи обновляются как часть одной транзакции. Опять же, 3 или 5 записей будут обновлены в одной транзакции.
  4. Номер 2 может повторяться несколько раз.
  5. Номер 3 может повторяться несколько раз.

Приложение должно отображать список записей истории за определенный период времени на основе записей, записанных только в виде отдельных транзакций (только пункты 1,3 и 5)

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

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

Есть ли более оптимальный способ управления таблицами аудита на основе AFTER (UPDATE, DELETE) TRIGGER для сущностей, охватывающих несколько таблиц?

Ответы [ 3 ]

1 голос
/ 26 января 2009

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

В нашем случае первичные таблицы назывались EntityAudit (где сущность была «основным» сохраняемым элементом), а все данные хранились в таблицах EntityHistory, связанных с аудитом. В нашем случае мы использовали уровень данных для бизнес-правил, поэтому было легко вставить правила аудита в сам уровень данных. Я считаю, что уровень данных является оптимальной точкой для такого отслеживания , если и только если все модификации используют этот уровень данных. Если у вас есть несколько приложений, использующих разные слои данных (или их вообще нет), то я подозреваю, что триггер, который создает основную запись, является практически единственным способом.

Если у вас нет дополнительной информации для отслеживания в Аудите (мы отслеживаем пользователя, который внес изменение, например, что-то не в главных таблицах), тогда я бы подумал о том, чтобы добавить дополнительный Аудит Идентификатор на самой «первичной» записи. Ваше описание, кажется, не указывает на то, что вы заинтересованы в незначительных изменениях в отдельных таблицах, а только на изменениях, которые обновляют весь набор сущностей (хотя я могу не прочитать это). Я сделал бы это, только если вас не волнуют мелкие правки. В нашем случае нам нужно было отслеживать все изменения, даже в связанных записях.

Обратите внимание, что использование таблицы Audit / Master имеет преимущество в том, что вы вносите минимальные изменения в таблицы истории по сравнению с исходными таблицами: один AuditID (в нашем случае Guid , хотя в нераспределенных базах данных вполне подойдут автономные номера).

0 голосов
/ 26 февраля 2009

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

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

Я понимаю, что вы спрашивали, как это сделать в триггерах БД. Я не знаю о SQL Server, но в Oracle вы можете преодолеть это, используя системный пакет DBMS_TRANSACTION.LOCAL_TRANSACTION_ID , чтобы вернуть идентификатор для текущей транзакции. Если вы можете извлечь эквивалентное значение SQLServer, то вы можете использовать его, чтобы связать обновления записей для текущей транзакции вместе в логический пакет.

0 голосов
/ 16 февраля 2009

Можете ли вы добавить столбец типа данных TimeStamp / RowVersion в основную таблицу сущности и связать все записи аудита с этим?

Но при обновлении любой из «дочерних» таблиц потребуется обновить главную таблицу сущностей, чтобы заставить TimeStamp / RowVersion измениться: (

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

Думая, что через вслух, может быть, лучше присоединить таблицу 1: 1 к главной сущности, которая содержит только идентификатор основной сущности и «номер версии» для записи - TimeSTamp / RowVersion, GUID, с приращением номер или что-то еще.

...