Разрабатывал на двух способах.
1. Все изменения в одной таблице: одна строчка-один реквизит (обычно справочники меняют по 1-3 реквизиту за раз, реже — всё). Хранилось: когда, кто, какой реквизит, значение до изменения (varchar, которое в клиенте превращалось в нужное значение, в том числе если там были ссылки на документы/справочники отображалось текущее значение этого об'екта и значение на момент изменения) + в оригинальной таблице было два поля: кто и когда создал (в основном пользователей эта информация интересовала, а история — только при разборках). Вся структура БД была описана метаданными: справочники, документы и их физическое представление. Отсюда при изменении физической структуры генерировался триггер на изменение, который и вносил в таблицу истории значение до изменения. Физического удаления не было — признаком «удалён» и кнопка «показать удалённые». Решение было простым, но сложнее было когда требовалась история по документу: по шапке получалось так же быстро, а по зависимым таблицам — только открыв об'ект и просмотрев построчно. Плюс некоторые неудобства для пользователя (хранится кто когда изменил и значение «до изменения», а не «после изменения»).
2. Немного видоизменённый вариант: В данных хранится текущая строка + кто и когда последний её изменял. При изменении этой строки значение до изменения кто, когда, какой объект теперь уже предпоследним изменил и весь объект на момент изменения (вся строка таблицы в XML). Также всё описано метаданными: по нужным реквизитам просто проставляются признаки «хранить историю», остальное додумывает клиент: генерирует запрос сохранения текущих данных в XML и сохраняет их в таблицу истории, а потом изменяет данные (и обновляет две колонки: кто и когда изменил). Думал будет сложнее первого варианта (с XML да ещё и на SQL не работал), но вроде получилось компактнее + легче было реализовать историю по документам с зависимыми таблицами (всё отображается в одном окне). Справочные значения разворачиваются и хранится текущее значение, соответственно получить на какой объект ссылался тогда документ (и может проследить уже его историю) затруднительно. Отсюда прожорливость (при изменении одного битового поля в таблице с 30 полями сохранит все 30 полей, причём сджойнив все зависимости), ну и XML тоже отнюдь не для скорости был придуман.
В обоих вариантах при реализации можно потерять одно из изменений: создание, последнее изменение или удаление.
Лично мне понравился первый вариант — гибче и проще (кроме запроса на извлечение исторических данных — там очень высокая этажерка), но пользователям оказалось не очень удобно видеть пореквизитные изменения — хотели видеть всю строку (неудобно когда при очередном изменении меняется новый реквизит и приходится текущее значение держать в уме), но вредителей так было легче искать. Во втором варианте придётся думать над отображением каши в зависимых таблицах (все строчки будут в куче и сложно разобрать какая строка истории к какой строке данных относится) и раскраской изменений по сравнению с предыдущим вариантом (хотя может подумать как хранить только изменившиеся реквизиты без остальных и существенных затрат времени на реализацию? там вроде куча проблем автоматически отпадёт).
Про остальные способы хранения изменений — очень хорошая
статья.