Темпоральная база данных - база данных, которая хранит изменения содержащихся в ней данных. Вместо изменения и удаления конкретных записей, в базу данных добавляется информация об изменении этих данных, сохраняя при этом старую информацию.
Для обеспечения темпоральности, все таблицы наследуют все столбцы от базовой таблицы Object, состоящей из столбцов:
- id
- time_create
- time_dead
- deleted
Столбцы time_create и time_dead служат для указания времени актуальности для конкретного id. Для одной строки таблицы, данные для текущего id актуальны с time_create по time_dead.
Столбец deleted используется при откате и восстановлении данных.
Чтобы просматривать самые актуальные данные, создается таблица с постфиксом _temp, которая, по сути, является представлением, сделанным из таблицы с помощью триггеров.
Символом * помечен столбец, показывающий акутальные данные. DEFAULT для time_dead - очень далекий момент времени, который не будет достигнут в обозримом будущем (для этого проекта принят за 01.01.3999 00:00:00
)
- INSERT - time_create для строки задается равным текущему времени, time_dead задается DEFAULT.
- UPDATE - time_create остается тем же, time_dead задается равным текущему времени. После добавляется новая строка, в которой time_create равно time_dead старой записи, а time_dead задается DEFAULT.
- DELETE - time_create остается тем же, time_dead задается равным текущему времени.
Главной возможностью темпоральной базы данных является возможность отката к предыдущим значениям и, по необходимости, возврата обратно, к более новым, актуальным данным.
Для этого создается отдельная таблица Journal, которая является журналом операций и записывает все операции манипуляции с данными.
- id - показывает, какой id изменился. Поскольку все таблицы наследуют от базовой таблицы Object, то
- time - время выполнения операции.
- op_name - название операции
- deleted - специальный флаг, который показывает, была ли отменена операция при откате.
Откат производится от самых новых записей.
Сначала выполняется поиск id, указанного в записи журнала, среди всех таблиц базы данных. После этого над строкой в таблице выполняются действия, зависящие от названия операции:
- INSERT - у строки в таблице взводится флаг deleted.
- UPDATE - у строки в таблице с актуальной информацией взводится флаг deleted, а у строки с предыдущими актуальными данными time_dead задается DEFAULT.
- DELETE - у строки в таблице time_dead задается DEFAULT.
После этого взводится флаг deleted у записи в журнале.
Схематично это будет выглядеть так:
До отката:
После отката:
Восстановление производится от самых старых отмененных записей.
Сначала выполняется поиск id, указанного в записи журнала, среди всех таблиц базы данных. После этого над строкой в таблице выполняются действия, зависящие от названия операции:
- INSERT - у строки в таблице сбрасывается флаг deleted.
- UPDATE - у строки без взведенного флага deleted устанавливается time_dead равное time в записи журнала. У строки со взведенным флагом deleted этот флаг сбрасывается.
- DELETE - у строки в таблице time_dead задается равным time в записи журнала.
После этого у записи в журнале сбрасывается флаг deleted.
Схематично это будет выглядеть так:
До восстановления:
После восстановления:
Для автоматического создания темпоральной базы данных написан скрипт sql_gen.py
с дополнительными функциями gen_lib.py
, в котором задаются нужные таблицы с их столбцами и их типами в виде:
tables = [
['table_name1', [
['row1', 'VARCHAR(50)'],
['row2', 'VARCHAR(50)']
]
],
['table_name2',
[
['row1', 'INT NOT NULL REFERENCES table_name1(id)'],
['row2', 'VARCHAR(50)'],
['row3', 'INT NOT NULL']
]
]
]
На выходе создается файл temp.sql
представляющий из себя готовый скрипт, достаточный для создания пустой темпоральной базы данных.
- При восстановлении возможно нарушение целостности: если какая-то запись в журнале была отменена, а после нее были проведенены какие-либо операции, затрагивающие id в отмененной записи (например, этот id был удален), то, при восстановлении этой записи может произойти нарушение целостности.