База данных – управление версиями данных в одной таблице

Я разрабатываю CMS, который имеет некоторые функции контроля версий. Он основан на MySQL Db.

Идея состоит в том, чтобы показать посетителям публичного сайта «определенную ревизию» данных и пользователей backoffice предварительный просмотр «последней редакции». Публикация чего-то просто означает установить «определенную ревизию», равную последней (и, возможно, удаление данных старых версий).

Я прочитал некоторые вопросы и ответы о теме на SO, большинство из них считают, что держать «старые» и «новые» строки в одной таблице плохи. Но, поскольку мне нужно объединять таблицы, все они «версируются», разбивая старые и новые в разных таблицах, также не идеальны (как приложение должно знать, является ли «контент» из одной редакции старым или новым, и, следовательно, найденный в таблице «истории» или нет?).

Поэтому я решил использовать только одну таблицу для каждого типа контента.

Дизайн, который я использовал: каждая таблица содержит столбец «ревизия INT NOT NULL» (часть первичного ключа вместе с столбцом идентификатора).

Изменение чего-то означает вставку новой строки с измененными значениями, увеличенной ревизией, но с тем же идентификатором.

Вставка чего-то означает вставку новой строки с увеличенным идентификатором и увеличенной ревизией.

Удаление чего-то означает вставку пустой строки с тем же идентификатором, увеличенной версией и флагом «thumbstone», установленным в «true».

Пример: есть страницы и есть «виды» («вид не в смысле MVC, вид в конкретном приложении»). «Представления» версии. Одна страница имеет много просмотров. Это (часть) «Просмотры».

CREATE TABLE `_views` ( `_id` int(11) NOT NULL, `_rev` int(11) NOT NULL, `_ts` BIT(1) DEFAULT b'0', `page` int(11) NOT NULL, `order` int(11) NOT NULL, PRIMARY KEY (`_id`,`_rev`) ) 

Мне нужно выбрать все представления, которые содержит страница, вплоть до «определенной ревизии» в порядке, указанном «заказ».

Этот запрос работает:

 SELECT * FROM ( SELECT * FROM `_views` WHERE `page` = :page AND `_rev` <= :revision ORDER BY `_rev` DESC ) AS `all` GROUP BY `_id` HAVING `_ts` = 0 ORDER BY `order` 

подзапрос выбирает все виды страницы, которые были однажды опубликованы (какая версия меньше или равна «опубликованной» ревизии). Внешний запрос группирует их до последней версии, удаляет группы с надписью и заказывает их по конкретным критериям приложения.

Поскольку для CMS масштабируемость и производительность имеют решающее значение, нет ли лучшего, более элегантного способа, чем подзапросы?

… или я должен просто сосредоточиться на кешировании?

Использование подзапросов для определения текущей версии – не лучший подход; вы действительно не хотите туда идти.

Более простой способ – добавить флаг, который расскажет вам о самой последней версии:

  `_rev` int(11) NOT NULL, `_current` BIT(1), 

Это требует, чтобы ручное UPDATE устанавливало флаг _current всякий раз, когда добавляется новая ревизия или _ts флаг _ts . Но, по крайней мере, это позволяет избежать выполнения подзапроса на каждом дисплее страницы.

В качестве альтернативы вы все равно можете разбить свои данные на _current и _history . Вместо этого вы просто создали представление для обоих случаев, если вам нужно снова присоединиться к наборам результатов:

  CREATE VIEW pages_all AS SELECT * FROM pages_current UNION ALL SELECT * FROM pages_history 

Также может быть возможно создать подтаблицу всех активных (без предварительного просмотра) ревизий, если вам нужно их часто группировать. Хотя это приведет к еще большему ручному микроуправлению, чем флаг _current, или просто просмотр таблицы _history.