У меня есть система CMS, которая хранит данные в таблицах вроде этой:
Entries Table
+----+-------+------+--------+--------+
| id | title | text | index1 | index2 |
+----+-------+------+--------+--------+
Entries META Table
+----+----------+-------+-------+
| id | entry_id | value | param |
+----+----------+-------+-------+
Files Table
+----+----------+----------+
| id | entry_id | filename |
+----+----------+----------+
Entries-to-Tags Table
+----+----------+--------+
| id | entry_id | tag_id |
+----+----------+--------+
Tags Table
+----+-----+
| id | tag |
+----+-----+
Я пытаюсь реализовать систему исправлений, немного похожую на SO. Если бы я просто делал это для таблицы записей
, я планировал просто хранить копии всех изменений в этой таблице в отдельной таблице. Поскольку я должен сделать это как минимум для 4 таблиц (таблица TAGS не требует изменений), это совсем не похоже на элегантное решение.
Как бы вы это сделали?
Обратите внимание, что мета-таблицы смоделированы в EAV (значение-атрибута объекта) .
Заранее благодарю.
Привет, я сейчас работаю над решением подобной проблемы, я решаю ее, разделив свои таблицы на две, контрольную таблицу и таблицу данных. Таблица управления будет содержать первичный ключ и ссылку на таблицу данных, таблица данных будет содержать ключ ревизии с автоматическим приращением и первичный ключ таблицы управления в качестве внешнего ключа.
взяв вашу таблицу записей в качестве примера
Entries Table
+----+-------+------+--------+--------+
| id | title | text | index1 | index2 |
+----+-------+------+--------+--------+
превращается в
entries entries_data
+----+----------+ +----------+----+--------+------+--------+--------+
| id | revision | | revision | id | title | text | index1 | index2 |
+----+----------+ +----------+----+--------+------+--------+--------+
, чтобы запросить
select * from entries join entries_data on entries.revision = entries_data.revision;
вместо обновления таблицы записей_данные вы используете оператор вставки, а затем обновляете ревизию таблицы записей новой ревизией таблицы записей.
Преимущество этой системы в том, что вы можете переходить к другим ревизиям, просто изменяя свойство ревизии в таблице записей. Недостаток в том, что вам нужно обновлять запросы. В настоящее время я интегрирую это в уровень ORM, поэтому разработчикам в любом случае не нужно беспокоиться о написании SQL. Еще одна идея, которую я пытаюсь придумать, - это централизованная таблица изменений, которую используют все таблицы данных. Это позволит вам описать состояние базы данных с помощью одного номера ревизии, аналогично тому, как работают номера ревизий субверсии.
Взгляните на этот вопрос: Как управлять версиями записи в базе данных
Почему бы не создать отдельную history_table для каждой таблицы (согласно принятому ответу на связанной вопрос)? Это просто составной первичный ключ из PK исходных таблиц и номер редакции. В конце концов, вам все равно нужно будет где-то хранить данные.
Для одного из наших проектов мы пошли следующим путем:
Entries Table
+----+-----------+---------+
| id | date_from | date_to |
+----+--------_--+---------+
EntryProperties Table
+----------+-----------+-------+------+--------+--------+
| entry_id | date_from | title | text | index1 | index2 |
+----------+-----------+-------+------+--------+--------+
Довольно сложно, но позволяет отслеживать полный жизненный цикл объекта. Таким образом, для запроса активных сущностей мы собирались:
SELECT
entry_id, title, text, index1, index2
FROM
Entities INNER JOIN EntityProperties
ON Entities.id = EntityProperties.entity_id
AND Entities.date_to IS NULL
AND EntityProperties.date_to IS NULL
Единственная проблема была в ситуации, когда сущность была удалена (поэтому мы поместили туда date_to), а затем восстановлена администратором. По данной схеме отследить такие трюки невозможно.
Общий недостаток любой подобной попытки очевиден — вам нужно написать тонны TSQL, где неверсионные БД будут использовать что-то вроде select A join B.