Механізм історичних таблиць та управління історичними даними

1. Огляд

Цей документ описує механізм збереження історичних даних у базі даних, принцип роботи історичних таблиць _hst, а також особливості їх оновлення у разі зміни структури основної таблиці. Він пояснює, як відстежуються зміни, які операції записуються до історичних таблиць і як забезпечується збереження попередніх версій даних.

2. Основні концепції

Платформа дозволяє створювати таблиці декларативно в XML-форматі. Під час розгортання Liquibase обробляє ці структури, генерує SQL-код і виконує його в базі даних PostgreSQL.

Для підтримки історичних змін таблиці створюються з атрибутом ext:historyFlag="true", який автоматично додає історичну таблицю (_hst) для відстеження змін.

3. Структура таблиць

При створенні таблиці з historyFlag="true", Liquibase генерує дві таблиці:

  • Основна таблиця (наприклад, protocols) — містить актуальні дані.

  • Історична таблиця (protocols_hst) –- містить всі зміни, які відбуваються в основній таблиці (додавання, оновлення, видалення).

Приклад XML-шаблону створення таблиць
<createTable tableName="protocols" ext:historyFlag="true">
    <column name="protocol_id" type="UUID">
        <constraints nullable="false" primaryKey="true" primaryKeyName="pk_protocols"/>
    </column>
    <column name="protocol_name" type="TEXT">
        <constraints nullable="false"/>
    </column>
</createTable>
Приклад SQL-структури основної таблиці
CREATE TABLE protocols (
    protocol_id UUID PRIMARY KEY,
    protocol_name TEXT NOT NULL,
    ddm_created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
    ddm_created_by TEXT NOT NULL,
    ddm_updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    ddm_updated_by TEXT
);
Приклад SQL-структури історичної таблиці
CREATE TABLE protocols_hst (
    protocol_id UUID NOT NULL,
    protocol_name TEXT NOT NULL,
    ddm_created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,
    ddm_created_by TEXT NOT NULL,
    ddm_dml_op CHAR(1) NOT NULL,
    ddm_system_id UUID NOT NULL,
    ddm_application_id UUID NOT NULL,
    CONSTRAINT pk_protocols_hst PRIMARY KEY (protocol_id, ddm_created_at)
);

4. Механізм історичних змін

4.1. Додавання записів

При вставці нового запису (INSERT) у головну таблицю, запис не дублюється в історичній таблиці. Історична таблиця починає вести історію тільки після першого оновлення або видалення.

Приклад вставки нового запису
INSERT INTO protocols (protocol_id, protocol_name)
VALUES ('550e8400-e29b-41d4-a716-446655440000', 'Protocol A');

4.2. Оновлення записів

При зміні даних (UPDATE) стара версія запису копіюється в історичну таблицю. У _hst зберігається вся історія змін.

Приклад оновлення запису
UPDATE protocols
SET protocol_name = 'Protocol A - Updated'
WHERE protocol_id = '550e8400-e29b-41d4-a716-446655440000';

4.3. Видалення записів

Якщо запис видаляється (DELETE), його копія переноситься в історичну таблицю _hst перед фізичним видаленням з основної таблиці.

Приклад видалення запису
DELETE FROM protocols
WHERE protocol_id = '550e8400-e29b-41d4-a716-446655440000';

5. Збереження історичних даних при зміні структури таблиць

Історичні таблиці реєстру фіксують усі зміни даних протягом їхнього життєвого циклу, зберігаючи оновлення, видалення та інші операції, що відбувалися з записами в основній таблиці. Це дозволяє зберігати повну історію змін, забезпечуючи аудит, прозорість і можливість відновлення попередніх версій інформації.

На цей час система не передбачає механізмів автоматичного очищення історичних таблиць _hst. Однак, якщо структура основної таблиці змінюється, створюється нова історична таблиця, яка зберігає дані відповідно до формату, що діяв на момент внесення змін. Це забезпечує коректне збереження історичних даних у їхньому початковому вигляді, узгодженому зі структурою таблиць, яка діяла в той час.

Важливо зазначити, що такий підхід не є механізмом "скорочення" історичних таблиць. Історичні записи не видаляються, а лише адаптуються до змін у структурі основної таблиці. Завдяки цьому історичні дані залишаються доступними та зберігаються у відповідному форматі незалежно від оновлень схеми.

Хоча функціональність політик збереження та архівування даних (retention policies and data archiving) наразі відсутня, її розробка розглядається.

  • Якщо в основну таблицю додається новий стовпець → створюється нова версія історичної таблиці (_hst_1, _hst_2 і т. д.).

  • Всі записи з _hst переносяться в нову таблицю _hst_1, а поточна _hst зберігає лише останню версію записів.

  • У результаті, якщо _hst містила кілька оновлень (UPDATE) одного запису, то в новій версії _hst залишається лише останній стан запису.

  • Попередні проміжні версії зберігаються в архівній таблиці _hst_1.