处理非自动递增ID的策略

时间:2011-06-28 16:40:01

标签: mysql increment

有人最近建议我删除一个仅用于存储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必须是唯一的。

有人能用简单的英语向我解释一下这通常是怎么做的吗?我想到了这一点,但如果我有正确的想法,它似乎没有比我以前的方法更清洁。以下是我假设的过程:

  • 从tag_translations
  • 中选择tag_id
  • 选择结果集中的最高数字+ 1
  • 制作新的查询(插入)
  • 定义一些额外的策略,以确保在以大致相同的微秒创建标记时,不会复制新的tag_id记录的ID

如果这是一个过程,我认为我最好坚持使用现有的架构来增加自动增量ID。我仍然需要做一个额外的查询来首先检查一个唯一的ID(我正在交易一个单独的联接今天插​​入)。如果在我需要独特的时候保持我的ID独特的头痛是我认为的那样,我可能想放弃这种方法并坚持我所拥有的。我的想法听起来好吗?

1 个答案:

答案 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(在外部添加)。
  • 此外,有些情况要求“保留”几个新ID而不是一次一个。在这种情况下,你会添加许多你需要的。根据上述变体,假设序列位于11,意味着检索的最后id10,而11是下一个ID。如果您需要7个新ID,则可以使用set id = last_insert_id(id) + 711已使用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的效果。