【问题标题】:Scoped/composite surrogate keys in MySQLMySQL中的作用域/复合代理键
【发布时间】:2010-10-18 22:04:44
【问题描述】:

这是我当前数据库的摘录(更改了表名以便于理解):

Pet(ownerFK, id, name, age)
Owner(id, name)

其中id 始终是代理键,由auto_increment 创建。

我想让代理键 Pet.idPet.ownerFK“限定”,或者换句话说,有一个复合键 [ownerFk, id] 作为我的最小键。我希望表的行为如下:

INSERT Pet(1, ?, "Garfield", 8);
INSERT Pet(1, ?, "Pluto", 12);
INSERT Pet(2, ?, "Mortimer", 1);

SELECT * FROM Pet;
  RESULT:
   Pet(1, 1, "Garfield", 8)
   Pet(1, 2, "Pluto", 12)
   Pet(2, 1, "Mortimer", 1)

我目前正在使用此feature of MyISAM,其中“您可以在多列索引的辅助列上指定AUTO_INCREMENT。在这种情况下,AUTO_INCREMENT 列的生成值计算为MAX(auto_increment_column) + 1 WHERE prefix=given-prefix。当您想将数据放入有序组时,这很有用。”

但是,由于各种(可能是显而易见的)原因,我想从 MyISAM 切换到 InnoDB,因为我需要在某些地方进行事务。

有没有什么方法可以用InnoDB实现这个效果?

我发现了一些关于这个问题的帖子,其中许多建议在插入之前对表进行写锁定。我对此不是很熟悉,但是对于这个来说,这不会是一个表写锁的大修吗?如果可能的话,我宁愿考虑使用写安全事务(我以前从未这样做过)——将Owner.current_pet_counter 作为辅助字段。

所以另一个可接受的解决方案是......

实际上,我不需要“作用域”ID 作为实际密钥的一部分。我实际的数据库设计使用了一个单独的“永久链接”表,它使用了这个“功能”。我目前使用它作为丢失交易的解决方法。我想到了以下替代方案:

 Pet(id, ownerFK, scopedId, name, age), KEY(id), UNIQUE(ownerFK, scopedId)
 Owner(id, name, current_pet_counter)

 START TRANSACTION WITH CONSISTENT SNAPSHOT;
 SELECT @new=current_pet_counter FROM Owner WHERE id = :owner_id;
 INSERT Pet(?, :owner_id, @new, "Pluto", 21);
 UPDATE Owners SET current_pet_counter = @new + 1 WHERE id = :owner_id;
 COMMIT;

我还没有在 MySQL 中使用过 transactions/transactionvars,所以我不知道这个是否会有严重的问题。 注意: 我不想重复使用曾经给宠物的ids。这就是我不使用MAX() 的原因。 这个解决方案有什么注意事项吗?

【问题讨论】:

    标签: mysql transactions innodb auto-increment composite


    【解决方案1】:

    我不这么认为。如果您确实必须拥有该架构,则可以使用事务来选择 MAX(id) WHERE ownerFK,然后插入。

    不过,我非常怀疑这种架构是否有充分的理由;主键现在也是关于键的事实,这可能会让数据库理论家不高兴。

    通常,您希望 'id' 本身真的是一个正确的主键,使用 ownerFK 进行分组,如果需要,还可以使用单独的 'rank' 列将宠物按每个所有者按特定顺序排列,和一个 UNIQUE 索引(ownerFK, rank)。

    【讨论】:

    • 我明白你的意思。我的实际数据库设计略有不同,我也不需要它成为主键的一部分。我用我正在评估的当前解决方案更新了问题。
    猜你喜欢
    • 2010-12-10
    • 2014-07-12
    • 2011-12-13
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    相关资源
    最近更新 更多