【问题标题】:Database - data versioning in single table数据库 - 单表中的数据版本控制
【发布时间】:2011-08-26 13:23:38
【问题描述】:

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

这个想法是向公共网站访问者展示数据的“特定修订版”,并向后台用户展示“最新修订版”的预览。发布某些东西只是意味着将“某些修订”设置为等于最新的(并且可能删除旧修订的数据)。

我已经阅读了一些关于 SO 主题的问答,其中大多数都认为在同一个表中保存“旧”和“新”行是不好的。但是,由于我需要加入表格,所有表格都“版本化”,在不同的表格中拆分新旧表格也不理想(应用程序如何知道来自一个修订版的“内容”是旧的还是新的,因此要是否在“_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`

子查询选择页面的所有视图,这些视图曾经“发布”(哪个版本小于或等于“发布”版本)。外部查询将它们分组到他们的最新修订版,删除具有拇指石的组并按应用程序特定标准对它们进行排序。

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

...还是我应该只专注于缓存?

【问题讨论】:

  • “拇指石”这件事又是什么目的?
  • 这是“墓碑”的另一种拼写。这是一个标志,标志着某事被“删除”(以此类推,已死)。所以可以通过删除这个“删除修订”轻松恢复

标签: php database versioning


【解决方案1】:

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

一个更简单的方法是添加一个标志,告诉您最新的修订:

   `_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 表的视图更多的手动微观管理。

【讨论】:

  • +1 用于存储当前版本。我认为这是最好的方法,创建一个 ON INSERT 触发器可以帮助使这个过程变得透明。
  • _current 标志的问题在于:什么是“当前”取决于查看了页面。管理员看到“最后”修订,普通访问者看到另一个“当前”修订。此外,管理员需要能够切换到他想要的任何版本(用于比较目的)我需要比较 UNION ALL 和子查询之间的性能命中。
  • @user913761:这听起来更像是一个应用程序编码问题。无论如何,您都需要为前端和后端动态调整 SQL。所以你不妨查询两个不同的表集,或者只在前端使用_current 标志。 (尽管我不确定我是否完全掌握了您需要以哪些方式使用修订分组。在您的情况下似乎有点复杂。) - UNION ALL VIEW 可能仍然有点帮助;据我了解,这只是一个附加,甚至不涉及临时表;你只需在后端使用它。
  • sql 语句保持不变,我只是将另一个修订传递给:revision 参数。但是,我可以为前端使用“_current”标志(定义“current”=“published”)
猜你喜欢
  • 2010-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-12
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多