如何在行版本化MySQL表(SCD类型2)中设置主键、自动增量和索引?

如何在行版本化MySQL表(SCD类型2)中设置主键、自动增量和索引?,mysql,indexing,primary-key,database-schema,scd,Mysql,Indexing,Primary Key,Database Schema,Scd,对于一个项目,我需要在MySQL数据库中实现行版本控制。在阅读了可能的解决方案后,我选择使用一个表并添加一个start\u date和end\u date列,指定该版本/行的活动时间 对于一行的多个版本,id列将是相同的。因此,它在表中不再是唯一的。现在我不知道如何设置主键(和其他索引),同时保持id列的自动递增活动 我看到两种选择。第一个是将id作为索引,如下所示: CREATE TABLE `thing` ( `id` int(11) unsigned NOT NULL AUTO_INC

对于一个项目,我需要在MySQL数据库中实现行版本控制。在阅读了可能的解决方案后,我选择使用一个表并添加一个
start\u date
end\u date
列,指定该版本/行的活动时间

对于一行的多个版本,
id
列将是相同的。因此,它在表中不再是唯一的。现在我不知道如何设置主键(和其他索引),同时保持
id
列的自动递增活动

我看到两种选择。第一个是将
id
作为索引,如下所示:

CREATE TABLE `thing` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  … other_columns …,
  `start_date` datetime NOT NULL,
  `end_date` datetime DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `thing` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  … other_columns …,
  `start_date` datetime NOT NULL,
  `end_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`,`start_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
id | some_column | start_date | end_date
---|-------------|------------|-----------
1  | Jonathn     | 2013-01-01 | 2013-01-02
1  | Jonathan    | 2013-01-02 | NULL
2  | James       | 2013-02-01 | NULL
另一个是将
id
start\u date
作为主键,如下所示:

CREATE TABLE `thing` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  … other_columns …,
  `start_date` datetime NOT NULL,
  `end_date` datetime DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `thing` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  … other_columns …,
  `start_date` datetime NOT NULL,
  `end_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`,`start_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
id | some_column | start_date | end_date
---|-------------|------------|-----------
1  | Jonathn     | 2013-01-01 | 2013-01-02
1  | Jonathan    | 2013-01-02 | NULL
2  | James       | 2013-02-01 | NULL
最好的选择是什么,特别是在考虑性能时


例如,数据如下所示:

CREATE TABLE `thing` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  … other_columns …,
  `start_date` datetime NOT NULL,
  `end_date` datetime DEFAULT NULL,
  KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `thing` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  … other_columns …,
  `start_date` datetime NOT NULL,
  `end_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`,`start_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
id | some_column | start_date | end_date
---|-------------|------------|-----------
1  | Jonathn     | 2013-01-01 | 2013-01-02
1  | Jonathan    | 2013-01-02 | NULL
2  | James       | 2013-02-01 | NULL

在本例中,我添加了“Jonathn”,但后来将其更改为“Jonathan”(同时保留相同的ID)。稍后添加另一行(“James”)。

第一个示例CREATE TABLE语句没有键*,第二个没有键*。我认为你的第二个例子就是你想要的:

CREATE TABLE `thing` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  … other_columns …,
  `start_date` datetime NOT NULL,
  `end_date` datetime DEFAULT NULL,
  PRIMARY KEY (`id`,`start_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
您可能希望也可能不希望id是自动递增列,但这主要是功能问题(您希望能够生成递增值还是自己插入它们),而不是逻辑设计或性能问题


*不幸的是,MySQL使用关键字
KEY
来指定索引。必须使用
唯一键
主键
语法指定键。

以上两种方法都不适用。首先确定随时间变化不变的密钥是什么,即标识您正在跟踪不同版本的内容的密钥(也称为“业务密钥”、“域密钥”、“自然密钥”)。将该属性/属性设置为具有开始日期的复合键。@sqlvogel我想我的问题还不够清楚。
id
不会因行的新版本而更改,因此这是不变键。@Jomathan,那么它不应该是自动递增的,因为自动递增会强制每行都有一个新值。@sqlvogel我已经快速尝试了问题中描述的选项,在这两种情况下,我都可以执行
插入到事物(id)值(1)中
为ID为1的现有行插入新版本。感谢您的解释,我将使用此设置。这(性能方面)是一种可接受的方法,还是您个人会推荐其他方法?因为我目前正在为数据库中的一个表实施此方法,所以我在考虑是否最好对PK使用end_date(而不是start_date)。其优点是,该表不接受两个id相同且为NULL的行作为结束日期(因此,您可以确保表中的id始终最多有一个当前行)。由于start_date和end_date都没有太多的语义含义,我不认为这有什么坏处。你怎么认为?