7

您是否曾经使用单独的表来“生成”数据库的人工主键(以及为什么)?我的意思是有一个包含两列、表名和当前 ID 的表 - 您可以通过简单地锁定具有该表名的行、获取键的当前值、递增它来为某个表获取新的“ID”减一,然后解锁该行。为什么您更喜欢标准整数标识列?

PS“想法”来自企业应用程序架构的福勒模式,顺便说一句......

4

6 回答 6

10

这称为 Hi/Lo 分配。

根据您的选择,您可以在您的表上使用 INSERT 触发器从该表中获取 ID 并在您获得 ID 之前或之后递增它。

这通常在您必须处理多个数据库引擎时使用。Oracle 中的自动增量标识符是通过 SEQUENCE 实现的,您可以在数据表上的 BEFORE INSERT TRIGGER 中使用 SEQUENCE.NEXTVALUE 递增该标识符。

相反,SQL Server 有 IDENTITY 列,本机自动递增,这由 DBE 本身管理。

为了让您的软件在这两种 DBE 上运行,您必须制定某种标准,然后最常用的“标准”就是主键的 Hi/Lo 分配。

这是其中一种方法。如今,使用 NHibernate 等 ORM 映射工具,它是通过配置提供的,因此您在应用程序和数据库方面都需要更少的关注。

编辑#1

因为这种操作不能用于全局范围,所以每个数据库或数据库模式都必须有一个这样的表。这样,每个模式都是相互独立的。但是,一个模式中的数据不能隐式移动到具有相同键的另一个模式中,因为它可能会与已经存在的行发生冲突。

至于安全模式,它与另一个模式或用户访问相同的数据库,因此对于特定的安全模式不应该存在额外的表。

于 2010-03-12T18:49:43.807 回答
5

每当您可以使用 sql server 的身份或 guid 功能时,您都应该这样做。但是,在某些情况下,这可能是不可能的。

一个例子是 sql server 每个表只允许一个标识列。很少有一个表包含需要私有 id 和公共 id 的记录,并且一个标识列的限制意味着将两者都生成为整数可能会很痛苦。您总是可以使用一个 guid,但您希望私有 id 上的整数以提高速度,并且您可能还希望公共 id 比 guid 更易于阅读。

在这种情况下,用于生成 id 的额外表是有意义的。但是,我会做一些不同的事情。表中仍有两列,但为每个真实表制作一个“影子”或“Id 映射”表。其中一列将是您的私人 ID(唯一约束),一列将是您的公共 ID(可能是增量值“7”或“13”或其他比“1”不那么明显的数字)。

这里的关键区别是您不想自己进行锁定。让 sql server 处理它。

于 2010-03-12T18:49:16.083 回答
3

我唯一一次使用它是当我在 BTrieve 中有一个应用程序时,它没有标识列。而且我还应该说,当他们尝试使用此表时,由于所有额外的读取和写入,当他们尝试导入数据时会导致速度大幅下降。我的朋友看了它并重写了他们是如何加快速度的,但这个故事的寓意是,如果你做错了这样的事情,可能会产生残酷的后果。

就个人而言,我不认为我会想要这样做。出错的可能性太大。两个人尝试使用相同的钥匙,因为他们在获取身份证之前忘记锁定桌子。如果可能的话,这似乎应该留给 RDBMS。正如 Will 提出的,尽量减少这种情况很容易,但如果你不知道自己在做什么,它可能会发生。

于 2010-03-12T18:46:57.897 回答
2

你根本不会喜欢它。

无论您通过使用该模式获得什么或成为 DB 不可知论者,您都会在头痛、支持和性能方面有所损失。

于 2010-03-12T19:05:25.880 回答
2

锁定具有该表名的行,获取键的当前值,将其加一,然后解锁该行

这听起来很简单,不是吗?

   UPDATE TableOfId
     SET Id += 1
   OUTPUT Inserted.Id
   WHERE Name = @Name;

实际上,这是一场灾难。应用程序中不会发生任何活动作为独立操作:所有操作都是事务的一部分。不能简单地“解锁”该行,因为“解锁”实际上只会在提交时发生。这意味着所有需要表上 Id 的事务都被序列化,并且在任何时候只有一个可以继续。这也意味着访问多个表的事务可能会在更新 Id 表时出现死锁,因为在实践中很难执行“获取下一个 Id”更新顺序。

为了避免完全序列化,需要在可以立即提交的单独的、独立的事务上获取 Id(通常是在 UPDATE 本身上隐式自动提交事务)。但这极大地复杂化了应用程序逻辑。每个操作都需要维护两个独立的数据库连接,一个用于执行正常的事务逻辑,另一个用于获取所需的 Id。即便如此,ID 的更新也可能成为一个热点,它仍然会导致可见的争用和阻塞(类似于网络应用程序中普遍存在的可怕的“更新页面点击计数 +1”)。

简而言之:使用 IDENTITY。身份生成针对高并发进行了优化。

于 2010-03-12T19:19:07.007 回答
1

当需要将在一个数据库中创建的数据迁移、备份、集群或暂存到另一个数据库时,我已经看到了这种模式。在这种情况下,首先您要确保主键不需要更改。其次是外键。第三,外部暴露的密钥或持久引用。

于 2010-03-12T19:04:48.230 回答