Блок контроля версий (БКВ) – набор полей таблицы данных, который обеспечивает поддержку версионности и хранения истории объектов. Например, у работника может изменяться должность, у должности в свою очередь может меняться оклад, кроме того, время от времени может меняться и название самой должности — в многомерном моделировании это называется Slowly Сhanging Dimensions (далее – SCD) — редко изменяющиеся измерения (справочники), то есть измерения, не ключевые атрибуты которых имеют тенденцию со временем изменяться.

Интегрируемая распределенная информационная система “Соиздатель”, проектное название “Китой” реализует основные методы SCD за счёт использования различного набора полей, которые определяют как история изменений может быть отражена в модели, всего существует 6 основных типов (методов).

Гибридный тип (тип 6 (1+2+3))

Для работы с данными в системе управления Китой применяется тип версионности 6, который был придуман Ральфом Кимболлом (Ralph Kimball) как комбинация вышеназванных методов и предназначен для ситуаций, которые они не учитывают или для большего удобства работы с данными. Он заключается во внесении дополнительной избыточности: берется за основу тип 2, добавляется суррогатный атрибут для альтернативного обзора версий (тип 3), и перезаписываются одна или все предыдущие версии (тип 1).

Конкретная реализация каждого типа версионности описаны далее.

Пример:

VERSION ID NAME POSITION_ID DEPT DATE_VALID DATE_EXPIRED CURRENT
1 1 Коля 21 2 11.08.2010 10:42:25 01.01.9999 1
1 2 Денис 23 3 11.08.2010 10:42:25 01.01.9999 1
1 3 Борис 26 2 11.08.2010 10:42:25 11.08.2010 11:42:25 0
2 3 Борис 26 2 11.08.2010 11:42:26 01.01.9999 1

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

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

Тип 0

Заключается в том, что данные после первого попадания в таблицу далее никогда не изменяются, возможно данные могут быть помечены в качестве удалённых. Этот метод практически никем не используется, т.к. он не поддерживает версионности. Он нужен лишь как нулевая точка отсчета для методологии SCD. Практическая реализация данного типа заключается в использовании следующих полей данных блока системной идентификации, USN Modified используется в качестве первичного ключа, String Identifier – для реализации возможности идентификации по тривиальному названию. Информационная система при данном типе контроля версий отслеживает только фактическое время и персону, которая создала запись и удалила её:

Название поля Тривиальное название Тип данных, длина Описание поля Значение по умолчанию
XXYY001 USN Modified 64-битное целое (Int64), NOT NULL Серийный номер, присваиваемый при изменении и/или создании записи Значение внешнего генератора последовательности уникальных целых чисел, изначально USN эквивалентны
XXYY004 String Identifier Строка unicode, 256 символов Строковое значение, используемое для однозначного визуального представления идентификатора создания сущности Уникальное строковое значение, генерируемое на основании USN или указываемое непосредственно пользователем
XXYY006 Date Created Дата и время Дата создания записи, присваиваемое автоматически, серверная дата GETDATE()
XXYY007 Owner Identifier 64-битное целое (Int64), NOT NULL Числовой идентификатор владельца записи, для системных (программируемых) учётных записей используются отрицательные значения
XXYY013 Date Deleted Дата и время, NULL Дата изменения данных записи, присваивается автоматически, серверная дата NULL – свидетельствует об отсутствии сведений об удалении записи
XXYY014 Killer Identifier 64-битное целое (Int64),  NULL Числовой идентификатор пользователя, который внёс изменения в запись, для системных (программируемых) учётных записей используются отрицательные значения NULL – свидетельствует об отсутствии сведений об удалении записи.

Тип 1

1 тип — это обычная перезапись старых данных новыми. В чистом виде этот метод тоже не содержит версионности и используется лишь там, где история фактически не нужна. Тем не менее, в некоторых СУБД для этого типа возможно добавить ограниченную поддержку версионности средствами самой СУБД (например, Flashback query в Oracle) или отслеживанием изменений через триггеры, ведением журнала изменений. ИРИС “Соиздатель” для поддержки синхронизации данных, контроля доступа к информации используют дополнительные поля информационных таблиц:

Тривиальное название Тип данных, длина Описание поля Значение по умолчанию
XXYY008 Date Modified Дата и время, NULL Дата изменения данных записи, присваивается автоматически, серверная дата NULL – свидетельствует об отсутствии внесения каких-либо изменений.
XXYY009 Editor Identifier 64-битное целое (Int64), NULL Числовой идентификатор пользователя, который внёс изменения в запись, для системных (программируемых) учётных записей используются отрицательные значения NULL – свидетельствует об отсутствии внесения каких-либо изменений.
XXYY010 Version Штамп времени, rowversion (timestamp) Версия изменений, внесённых в запись базы данных, используется для синхронизации данных

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

Тип 2

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

Название поля Тривиальное название Тип данных, длина Описание поля Значение по умолчанию
XXYY002 USN Created 64-битное целое (Int64), NOT NULL Серийный номер, присваиваемый при создании записи, используется в качестве идентификатора листа контроля доступа Значение внешнего генератора последовательности уникальных целых чисел, изначально USN эквивалентны
XXYY003 USN Parent 64-битное целое (Int64), NOT NULL Серийный номер родительского или наследуемого элемента, так же используется при наследовании разрешений от родительского или наследуемого объекта 0 – нет исходного или родительского элемента, принудительное прерывание наследования или связи с родительским элементом
XXYY011 Settings 64-битное целое (Int64), NOT NULL Флаги состояния, параметров записи. Четное значение флагов исключает запись из дальнейшей обработки – запись игнорируется при обработке пользователями. Изначально, при создании средствами сервера, поле приобретает значение равное 0 – none, назначение первого бита флага – enabled
XXYY012 State char(1) Статус записи в информационной системе, используется в дополнение к полю с параметрами записи, для более удобного визуального восприятия данных, и, последующего контроля состояния. При создании присваивается статус ‘C’ – создана, created, cloned, copied ‘C’

Поле USN Created при создании записи имеет значение, эквивалентное полю USN Modified и является общим связующим звеном для всех записей. В рамках информационной подсистемы в один момент времени для отображения используется только одна, активная запись из всего набора, остальные представляют собой архивные копии, например, при использовании функции автоматического сохранения. За счет поля Editor Identifier пользователь редактирует только свою версию записи, что исключает конфликты при сохранении данных во время совместной работы.

Пример таблицы данных с тривиальными названиями:

USN Modified USN Created Name Position Department State
1 1 Коля 21 2 H
2 2 Денис 23 3 A
3 1 Николай 26 2 A
4 4 Шелдон 22 3 A
5 4 Шелдон Купер 22 3 M

Где поле State имеет значения: A – Active, M – Modified, H – Historical и другие… Значение полей Settings и State – зависимы, изменение значения поле State приводит к изменению битовой маски, сохраняемой в поле Settings. В дополнение к изложенному, имея сведения о версиях данных, находящихся в работе или изменяемых в настоящий момент, для построения отчётов, должна приниматься версия данных, актуальная на момент до утверждения внесённых изменений, некоторое время должны сохраняться отклонённые варианты данных, возможно к ним будет необходимо вернуться и утвердить в замен.

Пример таблицы данных с тривиальными названиями:

USN Modified USN Created Name Position Department State Date Valid Date Expired
1 1 Коля 21 2 H 11.08.2010 10:42:25 21.02.2024 10:42:25
2 2 Денис 23 3 A 11.08.2010 10:42:25 01.01.9999 23:59:59
3 1 Николай 26 2 A 21.02.2024 10:42:25 01.01.9999 23:59:59
4 4 Шелдон 22 3 A 11.08.2010 10:42:25 01.01.9999 23:59:59
5 4 Шелдон Купер 22 3 M 21.02.2024 10:42:25 01.01.9999 23:59:59

Для исключения проблем с созданием первичного ключа из ID, Date Valid и Date Expired, в качестве даты конца версии по умолчанию стоит ‘01.01.9999’, использование NULL существенно усложняет процесс выборки данных. Для определённой даты можно использовать запрос (“where snapshot_date between DATE_VALID and DATE_EXPIRED” вместо “where snapshot_date>DATE_VALID and (snapshot_date < DATE_EXPIRED or DATE_EXPIRED is null)”. При такой реализации при увольнении сотрудника можно будет просто изменить дату конца текущей версии на дату увольнения вместо удаления записей о работнике.

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

Версионность второго типа вводит использование следующих полей:

Название поля Тривиальное название Тип данных, длина Сведения об индексе Описание поля Значение по умолчанию
XXYY015 Date Valid Дата и время, NOT NULL Может быть включен в первичный ключ (Primary key) Дата начала периода актуальности данных записи В качестве даты конца версии по умолчанию стоит максимальное значение даты, использование NULL существенно усложняет процесс выборки данных.
XXYY016 Date Expired Дата и время, NOT NULL Может быть включен в первичный ключ (Primary key) Дата окончания периода актуальности данных записи

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

Тип 3

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

ID UPDATE_TIME LAST_STATE CURRENT_STATE
1 1 11.08.2023 12:58:48 0 1
2 2 11.08.2022 12:29:16 1 1

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

Тип 4

Является одним из основных принципов совместной работы с данными. В хранилище для обработки данных к основной таблице A создаётся отдельная таблица H для хранения истории изменений. При такой реализации, например, варианты публикаций хранятся в отдельной таблице данных, и до момента утверждения одного из вариантов основная таблица A не обновляется. В начале процесса изменений запись из таблицы A переносится в таблицу Н, где с ней производятся некоторые изменения.

Утвержденная ответственным лицом запись в таблице H переносится в таблицу А, заменяя её. Дополнительные поля в основной и отдельной таблице при этом не используются.

Обычно этот тип используют для аудита изменений или создания архивных таблиц (в Oracle этот же 4-й тип можно получить из 1-го используя flashback archive). Подтипом или гибридом этого варианта (со вторым типом), как мне кажется, следует считать секционирование по признаку текущей версии с разрешенным перемещением строк, но это уже за гранью моделирования и скорее относится к администрированию.

Пример:

select * from emp

ID NAME POSITION_ID DEPT
1 Коля 21 2
2 Денис 23 3
3 Борис 26 2
4 Шелдон 22 3
5 Пенни 25 2

Пример:

select * from emp_history

ID NAME POSITION_ID DEPT DATE
1 Коля 21 1 11.08.2022 14:12:13
2 Денис 23 2 11.08.2020 14:12:13
3 Борис 26 1 11.08.2023 14:12:13
4 Шелдон 22 2 11.08.2019 14:12:13