某种每

某种每

问题描述:

我有它有一个ID(带自动递增主键)表中的主键值“不同的自动增量指标”,UID(键指的用户ID为例)和其他对我的问题没有任何影响。某种每

我要打,让调用它ID,不同的自动递增键每个UID条目。

所以,我会添加一个条目与UID 10,并且这个记录的ID领域将有因为UID有与值没有以前的条目。我将添加与UID 4及其ID一个新将,因为我有与UID 4 entried都已经是两个。

...非常明显的解释,但我想尽可能清楚地解释,因为我可以清楚地证明这个想法。

  1. 什么SQL引擎可以本地提供这样的功能? (非微软/甲骨文)
  2. 如果没有,我怎么能最好地复制它?也许触发?
  3. 此功能是否有更适合的名称?
  4. 如果您知道提供这种功能的非SQL数据库引擎,请将其命名,但我很好奇。

谢谢。

+1

你真的想达到什么目的?把这么多的“逻辑”放入主键和外键听起来似乎是一个坏主意。 –

+0

@a_horse_with_no_name例如,我想存储更改或用户完成的任何操作,所有这些操作都带有一个自动递增字段,用于以数字顺序排列他们所做的操作。为此,我需要为每个用户提供不同的表格,这显然是一个可怕的想法。 – 2011-09-24 16:48:25

+0

您听起来像是应该将更改与时间戳一起存储,然后在检索信息时按照该时间戳排序,以便按照完成的顺序进行排序。 –

MySQL的MyISAM引擎可以做到这一点。参见他们的手册,在章节Using AUTO_INCREMENT中:

对于MyISAM表,您可以在多列索引中的辅助列上指定AUTO_INCREMENT。在这种情况下,AUTO_INCREMENT列的生成值计算为MAX(auto_increment_column)+ 1 WHERE prefix = given-prefix。当您想要将数据放入有序组时,这非常有用。

该文档继续该段落后,显示一个示例。

MySQL中的InnoDB引擎不支持此功能,这是不幸的,因为在几乎所有情况下最好使用InnoDB。

无法在INSERT上锁定表的情况下,使用触发器(或任何限制为事务范围的SQL语句)无法模拟此行为。考虑的行动序列:

  1. 马里奥开始交易,并插入一个新行的用户4
  2. 比尔开始交易,并插入了用户新行4.
  3. 马里奥的会话触发了触发器来计算MAX (id)+1。您得到3.
  4. Bill的会话触发一个触发器来计算MAX(id)。我得到3.
  5. 比尔的会议完成他的INSERT和提交。
  6. Mario的会话尝试完成他的INSERT,但现在存在(userid = 4,id = 3)的行,所以Mario得到主键冲突。

一般来说,如果不进行某种同步,您将无法控制这些步骤的执行顺序。

对此的解决方案往往是:

  • 获取排它表锁。在尝试INSERT之前,锁定表。这是防止并发INSERT创建race condition所必需的,如上例所示。有必要锁定整个表,因为你试图限制INSERT,没有特定的行要锁定(如果你试图用UPDATE来控制对给定行的访问,你可以锁定特定的行)。但锁定表会导致访问表成为串行,这会限制吞吐量。

  • 在交易范围外进行。以不会从两个并发事务中隐藏的方式生成ID号。顺便说一句,这是AUTO_INCREMENT所做的。无论其执行顺序或提交顺序如何,两个并发会话都将获得唯一的id值。但是跟踪每个用户标识的最后生成的标识需要访问数据库或重复的数据存储。例如,一个memcached每个用户标识的密钥,可以是incremented atomically

这是比较容易确保刀片得到独特值。但很难确保他们连续得到序数值。另请考虑:

  • 如果您在事务中插入但后来回滚会发生什么?你已经在该交易中分配了id值3,然后我分配了值4,所以如果你回滚并且我承诺,现在有差距。
  • 如果由于表上的其他约束而导致INSERT失败(例如,另一列不为空)会发生什么?你也可以通过这种方式获得差距。
  • 如果你曾经删除一行,你是否需要重新编号为同一用户ID的所有以下行?如果您使用该解决方案,它对您的memcached条目会有什么影响?

SQL Server应该允许你这样做。如果你不能使用computed column(可能不是 - 有一些限制)来实现这个,你当然可以在trigger中实现它。

MySQL也可以让你实现这个通过触发器。

在评论中你问了关于效率的问题。除非你处理极端的数据量,否则与使用例如4字节的INT相比,存储8字节的DATETIME的开销并不大。

它也大量简化了您的数据插入,以及能够处理记录被删除而不会在您的序列中创建'洞'。


如果你确实需要这一点,小心的字段名。如果您的表格中有uidid,我希望id在该表中是唯一的,而uid指的是其他内容。也许,使用字段名称property_idamendment_id

在实施方面,通常有两种选择。


1)。触发器

实施方式各不相同,但逻辑保持不变。当你不指定RDBMS(比不了MS /甲骨文等)一般的逻辑很简单...

  • 开始交易(通常这是隐式已经开始内部触发)
  • 找到MAX(amendment_id)为在PROPERTY_ID插入
  • 更新与MAX(amendment_id) + 1
  • 新插入的值提交事务

事情要注意的是...
插入多个记录在同一时间
- -插入与amendment_id存在已填充
记录 - 更新改变现有记录


2)。一个存储过程

如果您使用存储过程来控制对表的写入操作,那么您将获得更多的控制权。

  • 隐含的,你知道你只处理一条记录。
  • 您只是不提供DEFAULT字段的参数。
  • 你知道什么更新/删除可以和不可能发生。
  • 你可以实现你喜欢的所有业务逻辑,而隐藏触发


我个人推荐的存储过程的路线,但触发器做的工作。

确保数据类型正确非常重要。

你所描述的是一个多部分的关键。所以使用多部分的键。不要试图将所有东西都编码成一个魔法整数,否则你会损害你的其他代码。

如果一条记录被(entity_id,version_number)识别,则接受该描述并直接使用它,而不是改变密钥的含义。你将不得不编写限制版本号的查询,但这没关系。数据库擅长这类事情。

version_number可能是一个时间戳,正如a_horse_with_no_name所示。这是一个不错的主意。使用时间戳而不是普通整数没有意义的性能劣势。你获得的是,意思是,这更重要。

您可以维护一个“最新版本”表格,其中每个entity_id仅包含最近的version_number的记录。这将为你更多的工作,所以只有这样做,如果你真的需要的性能。