MySQL 中的作用域/复合代理键

发布于 2024-07-17 02:23:40 字数 1886 浏览 4 评论 0原文

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

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

其中 id 始终是使用 auto_increment 创建的代理键。

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

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)

我当前正在使用这个 MyISAM 的功能,其中“您可以在多列索引中的辅助列上指定 AUTO_INCRMENT 在这种情况下,为 生成的值。 code>AUTO_INCRMENT 列的计算方式为 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,所以我不知道这是否会存在严重问题。 注意:我不想重复使用曾经给予宠物的id。 这就是为什么我不使用 MAX() 的原因。 此解决方案有任何注意事项吗?

Here's an excerpt of my current database (changed the table-names for an easier understanding):

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

Where id is always a surrogate key, created with auto_increment.

I want to have the surrogate key Pet.id to be "scoped" by Pet.ownerFK or in otherwords, have a composite key [ownerFk, id] as my minimum key. I want the table to behave like this:

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)

I am currently using this feature of MyISAM where "you can specify AUTO_INCREMENT on a secondary column in a multiple-column index. In this case, the generated value for the AUTO_INCREMENT column is calculated as MAX(auto_increment_column) + 1 WHERE prefix=given-prefix. This is useful when you want to put data into ordered groups."

However, due to various (and maybe obvious) reasons, I want to switch from MyISAM to InnoDB, as I need transactions at some places.

Is there any way how to achieve this effect with InnoDB?

I found some posts on this issue, many of them proposed to write-lock the table before insertion. I am not very familiar with this, but wouldn't be a table-write-lock a little-bit of an overhaul for this one? I rather thought of having write-safe transactions (which I never did before) if these are possible - having a Owner.current_pet_counter as an helper field.

So another acceptable Solution would be...

Actually I don't need the "scoped" ID to be part of the actual Key. My actual database design uses a separate "permalink" table which uses this 'feature'. I currently use it as a workaround for the missing transactions. I thought of the following alternative:

 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;

I haven't worked with transactions/transactionvars in MySQL yet, so I don't know whether there would be serious issues with this one.
Note: I do not want to reuse ids that have been given to a pet once. That's why I don't use MAX(). Does this solution have any caveats?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤檠 2024-07-24 02:23:40

我不相信是这样。 如果您确实必须拥有该模式,则可以使用事务来选择 MAX(id) WHERE OwnerFK,然后插入。

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

通常情况下,您希望“id”本身成为一个正确的主键,并使用ownerFK进行分组,如果需要,还可以使用一个单独的“rank”列来将每个所有者的宠物按特定顺序排列,以及一个UNIQUE索引超过(ownerFK,排名)。

I don't believe so. If you really had to have that schema, you could use a transaction to SELECT the MAX(id) WHERE ownerFK, then INSERT.

I'm very sceptical there's a good reason for that schema, though; the primary key is now also a fact about the key, which might make the database theorists unhappy.

Normally you'd want ‘id’ to really be a proper primary key on its own, with ownerFK used to group and, if you needed it, a separate ‘rank’ column to put pets in a particular order per owner, and a UNIQUE index over (ownerFK, rank).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文