有人最近建议我删除一个仅用于存储ID的自动递增表。我还没有接受这个,我只是在探索它是否实际上是a better solution than what I currently have。这会让我有一个像这样的表:
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必须是唯一的。
有人能用简单的英语向我解释一下这通常是怎么做的吗?我想到了这一点,但如果我有正确的想法,它似乎没有比我以前的方法更清洁。以下是我假设的过程:
如果这是一个过程,我认为我最好坚持使用现有的架构来增加自动增量ID。我仍然需要做一个额外的查询来首先检查一个唯一的ID(我正在交易一个单独的联接今天插入)。如果在我需要独特的时候保持我的ID独特的头痛是我认为的那样,我可能想放弃这种方法并坚持我所拥有的。我的想法听起来好吗?
答案 0 :(得分:2)
为了生成新的标记ID,有一个比select max(tag_id) + 1
更好的选项。您可以使用单个字段模拟MySQL中的序列/生成器,并使用last_insert_id()
获取参数的能力。以下内容创建序列:
create table tag_id_seq (id int not null default 0);
insert into tag_id_seq values (0);
创建序列后,您可以使用以下两个语句从中获取下一个ID:
update tag_id_seq set id = last_insert_id(id + 1);
select last_insert_id();
last_insert_id()
是特定于连接的,因此第一个语句基本上用于捕获仅执行它的连接的值,以及更新序列。第二个语句只是检索值。如果两个不同的连接使更新语句彼此非常接近,那么它们在last_insert_id()
中仍然会有不同的ID。
您可以将其包含在仅传递序列名称的函数中,然后在您真正创建新标记时调用它。这比具有单个tags
列的auto_increment
表格要好得多。
您可以使用当前使用的ID启用它,而不是从0
开始,而下一个ID为1
:
update tag_id_seq set id = (select coalesc(max(tag_id),0) from tag_translations);
update
声明还有其他变体:
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()
进行检索,这意味着您可以将11
用于17
(含)。该序列将更新为18
,即将检索的下一个ID。序列在许多情况下都有优势,这些只是一些:
auto_increment
列,但您仍需要一种生成ID的方法。在MySQL中这种做序列的重要之处在于该领域。这意味着您可以在几乎任何位置包含包含当前/下一个序列值的字段。
例如,您可以创建一个序列表,其中序列名称为1列,当前/下一个值字段为1列,而不是为每个序列设置数十个表1。 1个表中的数十行更加整洁:
create table sequences (
seqname varchar(50) primary key,
id int not null default 0);
(如果表是InnoDB,则使用行级锁定而不是表锁定。)
auto_increment
in InnoDB可能不会以您喜欢的方式行事。在启动时,它会相当于select max(id)+1
来重置计数器。这可以产生重绕和重新使用之前使用过的ID的效果。