数据库-单表中的数据版本控制


Database - data versioning in single table

我正在开发一个具有一些版本控制功能的CMS。它基于MySQL数据库。

这个想法是向公共站点访问者展示数据的"特定版本",并向后台用户展示"最新版本"的预览。发布某些内容只是意味着将"特定版本"设置为与最新版本相等(并且可能删除旧版本的数据)。

我读过一些关于SO的问题,他们中的大多数人认为在同一个表中持有"旧"answers"新"行是不好的。但是,因为我需要连接表,它们都是"版本化的",在不同的表中分割新旧表也不理想(应用程序如何知道一个修订的"内容"是旧的还是新的,因此要在"_history"表中找到吗?)。

所以我决定为每个"内容类型"只使用一个表。

我使用的设计:每个表都有一个"revision INT NOT NULL"列(主键的一部分,还有一个ID列)。

修改内容意味着插入一个包含修改值的新行,一个增量的修订,但ID相同。

插入内容是指插入一个ID和修订都增加的新行。

删除某些内容意味着插入具有相同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的组,并根据应用程序特定的标准对它们进行排序。

既然CMS的可伸缩性和性能是至关重要的,难道没有比子查询更好、更优雅的方式吗?

…还是应该专注于缓存?

使用子查询来确定当前版本并不是最好的方法;你真的不想去那里。

一个更简单的方法是添加一个标志,告诉你最新的版本:

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

这需要在添加新版本或更改_ts标志时手动更新以设置_current标志。但至少避免了在每个页面显示上执行子查询

作为替代,您仍然可以将数据拆分为_current_history表。然后,如果需要再次连接结果集,则只需在两个结果集上创建一个视图:

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

同样,如果您需要频繁地对它们进行分组,也可以创建一个包含所有活动(非thumbstone)修订的子表。尽管这会导致比_current标志或者仅仅是_history表的视图更多的手工微管理。