Концепция контроля версий для строк таблицы базы данных (не относится к хранению скриптов в GIT/SVN)

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

Думайте об этих «изменениях» как о действительно длительных транзакциях, которые сохраняются в базе данных и имеют продолжительность жизни от минут до лет.

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

Конечно, все это требует некоторой формы разрешения конфликтов, поскольку предлагаемые изменения могут находиться в противоречивых состояниях (например, изменение A предлагает удалить запись, а изменение B предлагает ее обновить — если изменение A будет зафиксировано первым, тогда изменение B придется отменить)

Я не нашел готового продукта, который может это сделать. Ближе всего к этому был Oracle Workspace Manager, но он не предусматривал изменения при изменении или возможности просмотра предлагаемых удалений. Единственный способ добиться этого — иметь набор общих столбцов в моих версионных таблицах:

Идентификатор корня: обязательно — установите один раз то же значение, что и первичный ключ, при создании первой версии записи. Он представляет собой первичный ключ за все время и копируется в каждую версию записи. Вы должны учитывать корневой идентификатор при именовании столбцов отношения (например, PARENT_ROOT_ID вместо PARENT_ID). Поскольку корневой идентификатор также является первичным ключом исходной версии, внешние ключи могут быть созданы против фактического первичного ключа — фактическая желаемая строка будет определяться фильтрами версий, определенными ниже.

Идентификатор изменения: требуется — каждая запись создается, обновляется и удаляется посредством изменения.

Копировано из ID: Nullable — null указывает на вновь созданную запись, not-null указывает, из какого ID записи эта строка была клонирована/разветвлена ​​при обновлении/удалении.

Действительно с даты/времени: Nullable — null указывает на предложенную запись, not-null указывает, когда запись стала текущей. К сожалению, нельзя разместить уникальный индекс для корневого идентификатора/действующего источника, поскольку для любого корневого идентификатора может быть несколько нулевых значений. (Если вы не хотите ограничиться одним предлагаемым изменением для каждой записи)

Действительно по дате/времени: Nullable — null указывает на текущий или предлагаемый, not-null указывает, когда это стало историческим. Технически не требуется, но помогает ускорить поиск текущих данных. Это поле может быть повреждено ручным редактированием, но в этом случае его можно восстановить из даты/времени вступления в силу.

Флаг удаления: логическое значение — устанавливается в значение true, когда предлагается удалить запись после того, как она станет текущей. Когда удаления зафиксированы, их дата/время вступления в силу устанавливается на то же значение, что и дата/время вступления в силу, отфильтровывая их из текущего набора данных.

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

SELECT * FROM table WHERE EFFECTIVE_FROM <= :Now AND (EFFECTIVE_TO IS NULL OR EFFECTIVE_TO > :Now)

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

SELECT * FROM table WHERE (CHANGE_ID IN :ChangeIds OR (EFFECTIVE_FROM <= :Now AND (EFFECTIVE_TO IS NULL OR EFFECTIVE_TO > :Now) AND ROOT_ID NOT IN (SELECT ROOT_ID FROM table WHERE CHANGE_ID IN :ChangeIds)))

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

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

Кто-нибудь знает готовый продукт, который я мог бы использовать? Это большой объем работы, связанный с этим управлением версиями, и вводит всевозможные проблемы.


person Ben    schedule 07.03.2019    source источник
comment
Какую базу данных вы тоже имеете в виду? SQL-сервер? Оракул?   -  person James A Mohler    schedule 07.06.2019
comment
Любая СУБД может быть использована для подделки этого, как описано выше (я сделал это в Oracle) - я ищу любое хранилище данных, которое может выполнять такой контроль версий данных из коробки.   -  person Ben    schedule 10.06.2019
comment
Если ваше редактирование отвечает на ваш вопрос, вы должны отменить это редактирование и вместо этого опубликовать его как ответ.   -  person CodeCaster    schedule 16.10.2019


Ответы (1)


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

Окончательная структура таблицы немного отличается — «Удалить флаг» превратилось в «Изменить действие», то есть «Добавить», «Удалить» или «Изменить».

Глобальная временная таблица использовалась для хранения текущего идентификатора/даты-времени изменения соединения и хранимой процедуры, созданной для ее заполнения после соединения. Это называется «контекст».

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

В результате вы обрабатываете версионные таблицы как обычные таблицы (и не используете суффикс _ROOT_ID для внешних ключей) для выбора, вставки, обновления и удаления.

В представлениях возвращается только действие «Изменить», и это единственное поле, отличающее версионную таблицу от обычной.

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

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

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

person Ben    schedule 17.10.2019