处理非自动递增 ID 的策略
最近有人建议我删除一个仅用于存储 ID 的自动递增表。我还没有接受这个,我只是在探索它是否实际上比我目前拥有的更好的解决方案。这会给我留下一个像这样的表:
create table tag_translations (
tag_id int not null,
language_id int not null,
tag_name varchar(255),
primary key (tag_id, language_id)
);
我将有 tag_id 的重复项,存储其他语言的标签翻译。
添加新标签时,我需要放弃在 tag_id 上使用自动增量,而是手动分配新 ID。除非它只是现有标签的翻译,否则新一批翻译插入的 ID 必须是唯一的。
有人可以用简单的英语向我解释一下这通常是如何完成的吗?我考虑过这一点,但如果我的想法正确的话,它似乎并不比我之前的方法更干净。我假设的过程是这样的:
- 从 tag_translations 中选择 tag_id
- 选择结果集中的最大数字 + 1
- 进行一个新查询(用于插入)
- 定义一些附加策略以确保当标签获取时新 tag_id 记录的 id 不会重复在或多或少相同的微秒内创建
如果这是这个过程,我认为我最好坚持使用现有的模式,即拥有一个附加表来自动递增 id。我仍然需要执行额外的查询来首先检查唯一的 id(今天我正在用单个连接来换取插入)。如果我认为在需要唯一性时保持 ID 唯一性会令人头疼,那么我可能想放弃这种方法并坚持使用我所拥有的方法。我的想法合理吗?
Someone recently suggested that I remove an auto incrementing table used solely for storing IDs. I have not yet gone with this, I'm just exploring whether it is in fact a better solution than what I currently have. This would leave me with a table like this:
create table tag_translations (
tag_id int not null,
language_id int not null,
tag_name varchar(255),
primary key (tag_id, language_id)
);
I'm going to have duplicates for tag_id, storing translations of the tag in other languages.
When adding new tags, I need to forgo using auto increment on the tag_id, and instead assign new ID's manually. Unless it's just a translation of an existing tag, the ID needs to be unique for the new batch of translated inserts.
Can someone explain to me, in plain English, how this is typically done? I thought on this, but it doesn't seem to be any cleaner than my previous approach, if I have the thinking right. Here's what I'm assuming the process is:
- Select tag_id from tag_translations
- Pick the highest number in the result set + 1
- Make a new query (for insertion)
- Define some additional strategy for ensuring that ids for new tag_id records are never duplicated when tags get created at more or less the same microsecond
If this is the process, I think I'm better off sticking with my existing schema of having an additional table to auto increment ids. I still have to do an additional query to first check for a unique id (I'm trading a single join down the road for an insert today). If the headache of keeping my IDs unique when they need to be unique is what I think it will be, I may want to abandon this approach and stick with what I've got. Is my thinking sound?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
要生成新标签 ID,有一个比
select max(tag_id) + 1
更好的选项。您可以使用单个字段和使用last_insert_id()
接受参数的能力。下面创建了序列:创建序列后,您可以使用如下 2 个语句从中获取下一个 id:
last_insert_id()
是特定于连接的,因此第一个语句基本上用于捕获值仅适用于执行它的连接,并更新序列。第二条语句只是检索值。如果 2 个不同的连接执行的更新语句彼此非常接近,它们仍然会在last_insert_id()
中隐藏不同的 id。您可以将其包装在一个函数中,仅向其中传递序列名称,然后在真正创建新标签时调用它。这比具有单个
auto_increment
列的tags
表要好得多。您甚至可以使用当前使用的 id 来启动它,而不是从
0
开始,下一个 id 为1
:更新
也有一些变化> 语句:id
字段表示下一个 id 应该是什么,而不是最后一个给出的 id 是什么。在这种情况下,如果它是新序列,则将id
开头为1
而不是0
,并使用set id = last_insert_id( id) + 1
(加上外面)。11
,这意味着最后检索到的id
是10
和11
> 是下一个 id。如果您需要 7 个新 ID,则可以使用set id = last_insert_id(id) + 7
。11
通过select last_insert_id()
检索,这意味着您将使用 ID11
到17
(含)。该序列将更新为18
,即下一个要检索的 id。序列在许多情况下都有优势,以下是其中一些:
auto_increment
列,但您仍然需要一种生成 id 的方法。这种在 MySQL 中执行序列的方式的重要之处在于字段。这意味着您几乎可以在任何地方拥有包含当前/下一个序列值的字段。
例如,您可以创建一个序列表,其中 1 列用于序列名称,1 列用于当前/下一个值字段,而不是拥有数十个表(每个序列 1 个表)。一张表中有几十行就整洁得多:
(如果表是 InnoDB,则使用行级锁定而不是表锁定。)
InnoDB 中的
auto_increment
可能不会按照您喜欢的方式运行。启动时,它执行相当于select max(id)+1
的操作来重置计数器。这可能会产生倒带和重新使用之前使用过的 id 的效果。For generating new tag ids, there is a better option than
select max(tag_id) + 1
. You can mimic sequences/generators in MySQL with a single field and the use oflast_insert_id()
's ability to take an argument. The following creates the sequence:After creating the sequence, you could get the next id from it with 2 statements like this:
last_insert_id()
is connection-specific, so the first statement basically serves to capture a value for only the connection that executed it, as well as update the sequence. The second statement just retrieves the value. If 2 different connections did the update statement very close to each other, they would both still have different ids tucked away inlast_insert_id()
.You can wrap this up in a function into which you pass merely the sequence name, then call it whenever you are really creating a new tag. This would work much better than your
tags
table that has the singleauto_increment
column.Instead of starting at
0
with the next id being1
, you can bring it up even with currently used ids:There are also variations on the
update
statement:id
field represent what the next id should be, rather than what the last id given was. In that case, you would startid
as1
instead of0
if it's a new sequence, and useset id = last_insert_id(id) + 1
(with the addition outside).11
, meaning the lastid
retrieved was10
and11
is the next id. If you need 7 new ids, you would useset id = last_insert_id(id) + 7
.11
is retreived withselect last_insert_id()
, meaning you would use ids11
to17
(inclusive). The sequence would be updated to18
, the next id that will be retrieved.Sequences have advantages in many circumstances, and these are a few:
auto_increment
column but you still need a way to generate ids.The important thing about this style of doing sequences in MySQL is the field. This means you can have the field containing the current/next sequence value almost anywhere.
For example, instead of having dozens of tables, 1 for each sequence, you can create a sequences table with 1 column for the sequence name and 1 column for the current/next value field. Dozens of rows in 1 table is much tidier:
(And if the table is InnoDB, row-level locking is used rather than table-locking.)
auto_increment
in InnoDB may not behave in a way you like. On startup, it does the equivalent ofselect max(id)+1
for resetting the counter. That can have the effect of rewinding and re-using ids that had been used previously.