База данных - версия данных в одной таблице - PullRequest
3 голосов
/ 26 августа 2011

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

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

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

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

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

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

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

Удаление чего-либо означает вставку пустой строки с тем же идентификатором, инкрементной ревизией и флагом «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`)
)

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

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

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`

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

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

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

1 Ответ

2 голосов
/ 26 августа 2011

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

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

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

Для этого требуется ручное ОБНОВЛЕНИЕ, чтобы установить флаг _current всякий раз, когда добавляется новая ревизия или изменяется флаг _ts. Но по крайней мере это позволяет избежать выполнения подзапроса на каждом показе страницы.

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

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

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

...