Comments 28
Насколько проседает производительность при вставках и изменениях в устоявшихся режимах?
Сильная потеря производительности может получиться только на таблицах с частыми обновлениями, или на таблицах с большими записями(т.к. там используется механизм TOAST и при обновлении такой строки постгрес сильно оптимизирует эту операцию)
https://github.com/michaelpq/pg_plugins/tree/master/decoder_raw — читает WAL и генерит SQL стейтменты
Все таки используется динамический SQL при каждой операции с таблицей.
Динамический SQL используется не при каждой операции, а только при изменении данных.
К тому же при вставке данных в таблицу логов не производится никаких проверок(внешние ключи)
Проседание производительности может получиться при массовой вставке, но мы отключаем логгирование в таких случаях
Я к тому, что можно ли было пользоваться форматом JSON для хранения логов конкретной записи? Сама «ячейка» логов (если так можно выразиться) является JSON-массивом, куда вы только добавляете данные.Такой способ вполне может переварить и изменение колонок и изменение данных логов через триггеры. И таблица логов вполне себе может быть одна. (не знаю, насколько критична эта схема будет по производительности под хорошей нагрузкой).
Как вариант можно добавить дробление таблицы с логами горизонтально по дате или как уже тут проделано по имени таблицы.
Насчет использования JSON не задумывались, можно попробовать
И ещё вопрос про обращение к таблице. Вызов напрямую или используете view?
Есть два основных варианта логирования изменений без дополнительных таблиц:
- просто редактирование записи с обновлением служебных полей — сложно всю историю и хранить, и смотреть
- создание новых записи при обновление с пометкой старых как архивных (собственно как сам постгресс делает, если ничего не путаю) — сложно выбирать текущее значений, проблемы с первичными ключами и уникальными индексами, да и простыми, раздувание таблицы с оперативными данными.
Проще логи хранить отдельно всегда, не пытаясь их прилепить к основной записи. Или даже вообще на уровне архитектуры приложения переходить на событийную модель и не хранить состояния явно (или явно только в целях кэширования), а редусить его из потока событий до заданного предела, то есть делая логи не служебными записями, а полноправными бизнес-событиями.
Причём как по мне тут прежде всего надо разобраться с самим понятием, а что есть «лог». И если уж быть честным, то у меня язык не поворачивается назвать такую систему логом) больше похоже на метаинформацию фаловой системы. Она не столь нужна для лога, сколько для быстрого получения информации которую вполне можно взять как раз из логирования, но скорость при этом критична.
по задумке автора интерес представляло только дата изменения и кто поменял, если запись удалялось то это даже не интересовало
Процентов в 90 случаев где-то за несколько месяцев эксплуатации бизнес начинает интересовать не только кто и когда поменял, но и что было до изменения. Причём уверены, что раз можем посмотреть кто последний поменял, то вытащить всю историю изменения как самой записи, так и метданных (кто, когда, откуда и т. п.) это максимум полчаса чтобы запрос написать сложный.
Что же касается множественного набора записей, то это в первую очередь прерогатива архитектуры.
По такому принципу как правило строятся системы версий. Вкратце, если запись создана с такими и только такими параметрами, то любое их изменение влечёт изменение зависимых от неё (или ссылающихся на неё) записей.
По такому принципу строят, к примеру, международный словарь стран и их кодов ISO-3166. Стоит стране поменять площадь государства как сразу обновляется её номер.
Проще логи хранить отдельно всегда, не пытаясь их прилепить к основной записи.
А тут я с Вами полностью согласен, так как цель логов не только сохранить предыдущее состояние объекта, но и дополнительную метаинформацию и при этом ни в коем случае не влиять на саму информацию своим существованием.
1.Удаленные записи продолжают лежать в таблице(нужно вносить изменения в существующие функции, дополнительные расходы при выборках)
2.Если одна запись обновляется неоднократно, теряется история изменений
3.Могут возникнуть ошибки при добавлении новых ограничений на таблицу, т.к. логгировать предполагалось не все таблицы, то логгируемая таблица вполне может ссылаться на нелоггируемую
эх извращаться так извращаться.
А что мешало в первом варианте что вы писали сделать следующее:
- Переименовать таблицу которую логируете, ну любое имя или префикс.
- Создать новое представление (view) с именем таблицы которое было до переименования чтобы он брал данные из таблицы без флага _deleted например
- Повесить тригеры на изменения данных во view (insert, update, delete)
Итого получаем, старые скрипты работают с view вместо таблицы и даже не замечают подмены, действия на данными во view обрабатываются тригерами
К тому в варианте с представлениями удаленные/обновленные записи будут влиять на производительность при SELECT`ах
Эт понятно как его делать, было бы интереснее посмотреть, как проходил ваш поиск, какие решения рассматривали. Какие были бизнес-требования (хотели параметры «до» и «после» или достаточно было SQL запросов — по ним и так понятно, что было до, а что стало)?
Кстати, https://github.com/pgaudit/pgaudit/blob/master/README.md — не смотрели или не подошел?
Аргументы.
1. При обновлении одной записи приходится сохранять всю запись.
2. Управление историей требует специальных инструментов и обработки каждой отдельной таблицы.
3. Изменение структуры таблицы требует изменения структуры таблицы лога, что опять же делается для каждой таблицы одинаково и в вашем вариенте не зависит от размера таблицы.
Как избавится от этих проблем можно посмотреть в Ultimate 2C
Аудит изменения данных PostgreSQL