您是否曾使用单独的表来“生成”DB的人工主键(以及为什么)?我的意思是拥有一个包含两列,表名和当前ID的表 - 通过简单地用该表名锁定行,获取键的当前值,增加它,您可以使用该表为某些表获取新的“ID”一个,解锁行。为什么您更喜欢这个而不是标准整数标识列?
P.S。 “想法”来自Fowlers模式的企业应用程序架构,顺便说一句......
答案 0 :(得分:10)
这称为Hi / Lo赋值。
根据您的选择,您可以在表上的INSERT触发器获取此表中的ID并在获取ID之前或之后递增它。
当您需要处理多个数据库引擎时,通常会使用此选项。 Oracle中的自动增量标识符是通过SEQUENCE进行的,您可以在数据表的BEFORE INSERT TRIGGER中使用SEQUENCE.NEXTVALUE进行增量。
相反,SQL Server有IDENTITY列,本地自动增量,这由DBE本身管理。
为了使您的软件能够在两个DBE上运行,您必须达到某种标准,然后用于此的最常见的“标准”是对主键的Hi / Lo分配。
这是其中一种方法。目前,使用NHMInate等ORM Mapping工具,它通过配置提供,因此您无需关心应用程序和数据库端。
编辑#1
因为这种操作不能用于全局范围,所以每个数据库或数据库模式必须有这样的表。这样,每个模式都与另一个模式无关。但是,一个模式中的数据不能使用相同的密钥隐式地移向另一个模式,因为它可能与已存在的行冲突。
对于安全模式,它访问与另一个模式或用户相同的数据库,因此特定安全模式不应存在其他表。
答案 1 :(得分:5)
每当你可以使用sql server的身份或guid功能时,你应该这样做。但是,有一些情况可能无法实现。
一个例子是sql server每个表只允许一个标识列。很少,表会有需要私有id和公共id的记录,并且一个标识列的限制意味着生成两者作为整数可能是一种痛苦。你总是可以使用一个guid,但是你想要私有id上的整数来提高速度,你可能也希望公共id比guid更具人性化。
在这种情况下,用于生成id的额外表格是有意义的。但是,我的做法有点不同。表中仍有两列,但为每个真实表制作一个“阴影”或“Id映射”表。其中一列将是您的私人ID(唯一约束),其中一个将是您的公共ID(可能是增量值为'7'或'13'的身份或其他不如'1'明显的数字)。
这里的关键区别是你不想自己做锁定。让sql server处理它。
答案 2 :(得分:3)
我曾经使用过的唯一一次是我在BTrieve有一个应用程序,而且它没有标识列。我还应该说,当他们试图使用这个表时,由于所有额外的读写操作,它在尝试导入数据时导致了大幅减速。我的朋友看着它,并重写了他们是如何做到的,以加快速度,但故事的道德是,如果你做错了这样的事情,可能会有残酷的后果。
就个人而言,我认为我不想这样做。错误的可能性太大了。两个人尝试使用相同的密钥,因为他们忘记在抓住id之前锁定表。这似乎应该留给RDBMS,如果可能的话。正如Will提出的那样,很容易将这种情况降到最低,但如果你不知道自己在做什么,就可能发生这种情况。
答案 3 :(得分:2)
你根本不喜欢它。
无论您通过使用该模式获得什么或成为数据库不可知,您都会在头痛,支持和性能方面受到损失。
答案 4 :(得分:2)
这听起来很简单,不是吗?使用该表名锁定行, 获取密钥的当前值, 将它递增1,然后解锁 行
UPDATE TableOfId
SET Id += 1
OUTPUT Inserted.Id
WHERE Name = @Name;
实际上,这是一场灾难。应用程序中没有活动作为独立操作发生:所有操作都是事务的一部分。人们不能简单地“解锁”该行,因为“解锁”实际上只会在提交时发生。这意味着所有需要表上的Id的事务都是序列化的,只有一个可以随时进行。这也意味着访问多个表的事务可能会在更新ID表时发生死锁,因为在实践中强制执行“获取下一个Id”更新顺序很难。
为了避免完全序列化,需要在可以立即提交的单独的独立事务上获取ID(通常在UPDATE本身上隐式自动提交事务)。但这极大地使应用程序逻辑复杂化。每个操作都需要维护与数据库的两个独立连接,一个用于执行常规事务逻辑,另一个用于获取所需的ID。即使这样,Ids的更新也会成为一个热点,它仍然可能导致可见的争用和阻塞(类似于网络应用程序中流行的可怕的'更新页面点击计数+1')。
简而言之:使用IDENTITY。身份生成针对高并发性进行了优化。
答案 5 :(得分:1)
我已经看到在一个数据库中创建的数据需要迁移,备份,聚集或转移到另一个数据库时使用的这种模式。在这种情况下,首先要确保主键不需要更改。其次是外键。第三,外部暴露的钥匙或耐用的参考。