没有auto_increment的唯一ID

时间:2014-09-18 01:04:06

标签: mysql sql

我有一个带有非自动递增主键的现有架构。该密钥在十几个其他表中用作外键。

我继承了一个主要性能问题的程序。目前,当向此表添加新行时,这就是创建新唯一ID的方式:

1) a query for all existing primary key values is retrieved
2) a random number is generated
3) if the number does not exist in the retrieved values, use it, otherwise goto (2)

该应用程序是多线程和多服务器,因此在启动时只需抓取现有的ID就不是一个选项。我没有来自启动请求的唯一信息来获取并转换为伪唯一值(如成员ID)。

据我所知,理论上可以对内部进行手术,以便为现有的主键添加自动增量。我理解也可以系统地删除指向该表的所有外键,然后创建 - 重命名 - 插入表的新版本,然后添加回外键,但此表格格式由第三方应用程序决定,如果我搞砸了,那么坏事就会发生。

有没有办法利用sql / mysql来提出唯一的行值?

我最接近的是从大空间中随机选择一个数字并希望它在数据库中是唯一的,然后在发生奇数碰撞时重试。

想法?

4 个答案:

答案 0 :(得分:2)

如果表具有未用于外键引用的主键,则删除该主键。目标是使列成为自动递增的主键。

因此,寻找最大值,然后以下应该做你想做的事情:

alter table t modify id int not null auto_increment primary key;
alter table t auto_increment = <maximum value> + 1;

我认为没有必要明确设置auto_increment值,但我想确定。

答案 1 :(得分:0)

我认为您可以选择SELECT MAX(&#39; strange-id-column&#39;)+ 1。该值将是唯一的,您可以使用INSERT代码将该sql代码放在事务中,以防止错误。

答案 2 :(得分:0)

回退所有主键值列表(对于大集合),然后生成伪随机值并通过对列表进行检查来验证它是唯一的,这似乎真的很昂贵。

我用这种方法看到的一个大问题是,当序列以相同的种子值启动时,伪随机数生成器将生成相同的值序列。

如果发生这种情况,则碰撞后碰撞后会发生碰撞,直到序列达到尚未使用的值。下次它发生时,你会再次遍历整个列表,再添加一个值。

我不明白为什么价值必须是随机的。


如果要求伪随机性,并且升序值可以,那么如果我不想对现有表做任何更改,我会怎么做:

我创建了另一个具有auto_increment列的“id-generator”表。我对该表执行插入以生成id值。

我没有运行查询来从现有表中提取所有现有id值,而是在“id-generator”表中执行INSERT,然后执行SELECT LAST_INSERT_ID()检索我刚插入的行的id,并将其用作“生成的”id值。

基本上,模拟Oracle SEQUENCE对象。没有必要在“id-generator”表中保留所有行。因此,我可以对id值小于最大id值的所有行执行DELETE。


如果 要求伪随机性( shudder ),我可能只是尝试将INSERT作为查找密钥是否存在的方法。如果插入因重复键而失败,我将再次尝试使用不同的id值。

来自伪随机生成器的重复序列让我感到害怕......如果我连续几次碰撞......这些是来自先前使用过的序列,还是来自不同序列的值。我没有任何了解的方法。放弃序列并使用新种子重新启动,如果以前使用了该种子,我将追逐另一系列先前生成的值。

答案 3 :(得分:0)

对于低级别的并发(平均并发正在进行的插入<1),您可以使用乐观锁定来获得唯一的ID,而无需自动递增:

  1. 为此功能设置一个单行表,例如:

create table last_id (last_id bigint not null default 0);

  1. 要获取下一个ID,请在您的应用代码中检索此值,应用newId函数,然后尝试更新该值,例如:
select last_id from last_id; // In DB
newId = lastId + 1 // In app code
update last_id set last_id=$newId where last_id=$lastId // In DB

检查已更新的行数。如果它是0,则另一台服务器击败了您,您应该返回到步骤1。