如何在数据库中存储可版本化的数据?

时间:2017-04-24 12:40:59

标签: mysql mongodb database-design mongoose doctrine-orm

我想在即将推出的网络应用中实现一些暂存/版本控制功能。

虽然我在下面提到了MySQL / Doctrine和MongoDB / Mongoose这些标签,但实际上我并没有这样做。这些只是我经常使用的。我会选择最适合的技术。

基本上我想让我的用户恢复更改,保存草稿(分支),发布更改(合并/提交)等等。就像git对代码一样,我希望这种行为适用于数据。

我知道这种行为在很大程度上取决于应用程序代码,但首先我需要找到合适的数据库模式。

虽然这对简单的表来说并不那么难,但是当我有多个关系的表时,我很难找到一个好的/干净的解决方案。我能想到的每种方法都会产生大量冗余数据,或者看起来太复杂。

想象一下以下数据,其中每个帖子可以有多个标签

-- Create syntax for TABLE 'post'
CREATE TABLE `post` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`id`),
  KEY `name` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- Create syntax for TABLE 'post_tag'
CREATE TABLE `post_tag` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `post_id` int(11) DEFAULT NULL,
  `tag_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- Create syntax for TABLE 'tag'
CREATE TABLE `tag` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `label` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

在每次更改时复制整个post和post_tag表感觉不对。特别是因为我最终会得到另外5张相关的表格。

当与包含二进制数据或大字符串的表具有OneToMany关系时,情况更糟。每次更改都无缘无故地复制它们会导致大量无用的数据。

但也许这是要走的路?

1 个答案:

答案 0 :(得分:0)

你的post肯定超过id ?? (如果是,请编辑以添加省略号或其他内容。)

抛出Tag表。从id投掷post_tag并将tag_id替换为label。这是添加"标签的好模式"到"帖子":

CREATE TABLE `post_tag` (
  `post_id` int(11) NOT NULL,
  `tag` varchar(64) NOT NULL,
  PRIMARY KEY (post_id, label),  -- also prevents duplicate entries
  INDEX(tag, post_id)            -- for going the other way
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Rick's RoTs之一:"正常化,但不要过度正常化。"还有一点:在适当的时候使用UNSIGNED和/或NOT NULL

以上仅解决"标记"。如果您想讨论版本控制,请将其拆分为一个单独的问题。将两个不相关的问题放在一起并不好。 (当然,"标记" 可能是"版本控制"的工具,但我认为不是。)