2016-08-01 3 views
1

Я прошел через этот post для рекордного уровня управления версиями таблиц. Я заметил, что архитектура имеет дело с использованием таблиц истории. Тем не менее, мой сценарий не требует откат, а поиск точек во времени. Здесь я попытался разработать дизайн, используя одну таблицу для управления версиями. Обратите внимание, что это голые данные таблицы костей (без ограничений, индексов и т. Д.). Я намерен индексировать на основе id, так как это включает в себя предложение group by в столбце.Управление версиями базы данных без таблиц истории

К примеру, у меня есть таблица тест, где

идентификатора является идентификатором,

modstamp является временной меткой данных (никогда не нуль)

В дополнении к столбцы выше, таблица будет содержать бухгалтерские колонки

local_modstamp - это t imestamp, при котором запись была обновлена ​​

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

Во время резервного копирования, все записи получаются из источника и вставили, где записи будут иметь значения local_modstamp = нуль и del_stamp = null.

id |modstamp     |local_modstamp |del_modstamp | 
---|---------------------------|---------------|-------------| 
1 |2016-08-01 15:35:32 +00:00 |    |    | 
2 |2016-07-29 13:39:45 +00:00 |    |    | 
3 |2016-07-21 10:15:09 +00:00 |    |    | 

После записи получаются, эти сценарии для обработки данных (при условии, опорное время [ref_time] это время, при котором процесс выполняется):

  1. Вставка как обычно.

  2. Обновление: обновите самую последнюю запись с помощью local_modstamp = ref_time. Затем вставьте новую запись. Запроса будет: обновления тестового набора local_modstamp = где ID = и local_modstamp не утратившее del_modstamp не является нулевой вставки в тестовые значения (...)

  3. Удалить: Обновление самого последнюю записи с del_modstamp = ref_time. Тест обновление устанавливается del_modstamp = где идентификатор = и local_modstamp не утратившим del_modstamp не является нулевым

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

select id, max(modstamp) from test where modstamp <= <ref_time> and (del_modstamp is null || del_modstamp <= <ref_time>) group by id; 

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

Если нет, я полагаю, что вероятным решением является установка local_modstamp в последние записи. Это потребует обновления логики с использованием max (local_modstamp) в случае обновлений. Могу ли я сохранить существующую архитектуру для получения данных о времени?

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

ответ

1

Представляем версию нормальной формы. Рассмотрим эту таблицу:

create table Entities(
    ID  int identity primary key, 
    S1  [type], -- Static data 
    Sn  [type], -- more static data 
    V1  [type], -- Volatile data 
    Vn  [type] -- more volatile data 
); 

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

Перемещения Летучих атрибутов в отдельную таблицу:

create table EntityVersions(
    ID  int not null, 
    Effective date not null default sysdate(), 
    Deleted bit not null default 0, 
    V1  [type], 
    Vn  [type], 
    constraint PK_EntityVersions primary key(ID, Effective), 
    constraint FK_EntityVersionEntity foreign key(ID) 
     references Entities(ID) 
); 

В таблице Сущности больше не содержит летучие атрибуты.

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

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

Например, таблица сотрудников со следующими атрибутами:

EmployeeNum, HireDate, FirstName, LastName, PayRate, Dept, PhoneExt 

EmployeeNum будет, конечно же, быть статическими вместе с HireDate и FirstName. PhoneExt может время от времени меняться, но нам все равно. Поэтому он обозначается как статический. Конечная конструкция:

Employees_S 
=========== 
    EmployeeNum (PK), HireDate, FirstName, PhoneExt 

Employees_V 
=========== 
    EmployeeNum (PK), Effective (PK), IsDeleted, LastName, PayRate, Dept 

1 января 2016 года мы наняли Салли Смит. Статические данные вставляются в Employees_S, генерируя значение EmployeeNum 1001. Мы используем это значение, чтобы также вставить первую версию.

Employees_S 
=========== 
    1001, 2016-01-01, Sally, 12345 

Employees_V 
=========== 
    1001, 2016-01-01, 0, Smith, 35.00, Eng 

1 марта, она получает повышения зарплаты:

Employees_S 
=========== 
    1001, 2016-01-01, Sally, 12345 

Employees_V 
=========== 
    1001, 2016-01-01, 0, Smith, 35.00, Eng 
    1001, 2016-03-01, 0, Smith, 40.00, Eng 

1 мая, она выходит замуж:

Employees_S 
=========== 
    1001, 2016-01-01, Sally, 12345 

Employees_V 
=========== 
    1001, 2016-01-01, 0, Smith, 35.00, Eng 
    1001, 2016-03-01, 0, Smith, 40.00, Eng 
    1001, 2016-05-01, 0, Jones, 40.00, Eng 

Обратите внимание, что версии одного и того же лица, иные, чем что Эффективные даты не могут быть одинаковыми, полностью независимы друг от друга.

Чтобы увидеть текущее состояние работника 1001 выглядит, вот запрос:

select s.EmployeeNum, s.HireDate, s.FirstName, v.LastName, v.PayRate, v.Dept, s.PhoneExt 
from Employees_S s 
join Employees_V v 
    on v.EmployeeNum = s.EmployeeNum 
    and v.Effective = (select Max(Effective) 
         from Employees_V 
         where EmployeeNum = v.EmployeeNum 
          and Effective <= SysDate()) 
where s.EmployeeNum = 1001 
    and v.IsDeleted = 0; 

Вот прохладная часть. Для того, чтобы увидеть, что состояние работника 1001 выглядел как на, скажем, 11 фев вот запрос:

select s.EmployeeNum, s.HireDate, s.FirstName, v.LastName, v.PayRate, v.Dept, s.PhoneExt 
from Employees_S s 
join Employees_V v 
    on v.EmployeeNum = s.EmployeeNum 
    and v.Effective = (select Max(Effective) 
         from Employees_V 
         where EmployeeNum = v.EmployeeNum 
          and Effective <= '2016-02-11') 
where s.EmployeeNum = 1001 
    and v.IsDeleted = 0; 

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

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

Employees_S 
=========== 
    1001, 2016-01-01, Sally, 12345 

Employees_V 
=========== 
    1001, 2016-01-01, 0, Smith, 35.00, Eng 
    1001, 2016-03-01, 0, Smith, 40.00, Eng 
    1001, 2016-05-01, 0, Jones, 40.00, Eng 
    1001, 2016-09-01, 0, Jones, 50.00, Mkt 

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

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

+0

Если я выполняю удаление, будет ли последняя версия отмечена 1 или она будет вставлена, а затем отметьте delete с помощью 1? Это повлияет на запрос 'и v.IsDeleted = 0;' в запросе. Например, Салли покидает компанию в 2016-10-01, но я должен запросить, что такое состояние на 2016-06-01, будет игнорировать isDeleted в статье достичь цели? Я задаюсь вопросом, следует ли нормализовать таблицы. Я поддерживаю несколько тысяч в схеме, и нормализация их на две не раздувает таблицу. Можно ли его портировать в одну и ту же таблицу? – dmachop

+0

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

+0

PK статичен, и опыт показывает, что редко других статических атрибутов нет. Однако вам все еще нужны две таблицы, даже если главная таблица содержит только PK. Вам нужна неверсированная главная таблица, чтобы быть целью FKs из других таблиц. Если вы читаете различные схемы управления версиями, большой, непреодолимой проблемой всегда была нехватка ссылочной целостности. Этот (vnf) решает эту проблему. – TommCatt