/temporal_db

My realisation of temporal database with PostgreSQL

Primary LanguagePython

Темпоральная база данных

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

Обеспечение темпоральности

Для обеспечения темпоральности, все таблицы наследуют все столбцы от базовой таблицы Object, состоящей из столбцов:

  • id
  • time_create
  • time_dead
  • deleted

Столбцы time_create и time_dead служат для указания времени актуальности для конкретного id. Для одной строки таблицы, данные для текущего id актуальны с time_create по time_dead.

Столбец deleted используется при откате и восстановлении данных.

tables

Чтобы просматривать самые актуальные данные, создается таблица с постфиксом _temp, которая, по сути, является представлением, сделанным из таблицы с помощью триггеров.

Обработка операций

operations

Символом * помечен столбец, показывающий акутальные данные. 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, которая является журналом операций и записывает все операции манипуляции с данными.

journal

  • id - показывает, какой id изменился. Поскольку все таблицы наследуют от базовой таблицы Object, то
  • time - время выполнения операции.
  • op_name - название операции
  • deleted - специальный флаг, который показывает, была ли отменена операция при откате.

Связь записей в журнале и строк в таблицах

jounal_ref

Откат к старым значениям

Откат производится от самых новых записей.

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

  • INSERT - у строки в таблице взводится флаг deleted.
  • UPDATE - у строки в таблице с актуальной информацией взводится флаг deleted, а у строки с предыдущими актуальными данными time_dead задается DEFAULT.
  • DELETE - у строки в таблице time_dead задается DEFAULT.

После этого взводится флаг deleted у записи в журнале.

Схематично это будет выглядеть так:

До отката:

jounal_ref

После отката:

journal_cancel

Восстановление данных

Восстановление производится от самых старых отмененных записей.

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

  • INSERT - у строки в таблице сбрасывается флаг deleted.
  • UPDATE - у строки без взведенного флага deleted устанавливается time_dead равное time в записи журнала. У строки со взведенным флагом deleted этот флаг сбрасывается.
  • DELETE - у строки в таблице time_dead задается равным time в записи журнала.

После этого у записи в журнале сбрасывается флаг deleted.

Схематично это будет выглядеть так:

До восстановления:

journal_cancel

После восстановления:

jounal_ref

Автогенерация темпоральной базы данных

Для автоматического создания темпоральной базы данных написан скрипт 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 представляющий из себя готовый скрипт, достаточный для создания пустой темпоральной базы данных.

TO-DO

  • При восстановлении возможно нарушение целостности: если какая-то запись в журнале была отменена, а после нее были проведенены какие-либо операции, затрагивающие id в отмененной записи (например, этот id был удален), то, при восстановлении этой записи может произойти нарушение целостности.