没有auto_increment的唯一ID

问题描述 投票:1回答:4

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

我继承了一个主要性能问题的程序。目前,当向此表添加新行时,这是创建新唯一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来提出独特的行值?

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

想法?

mysql sql
4个回答
2
投票

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

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

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

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


0
投票

我想你可以SELECT MAX('strange-id-column')+ 1。该值将是唯一的,您可以将该sql代码放在具有INSERT代码的事务中,以防止出错。


0
投票

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

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

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

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


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

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

我没有运行查询来从现有表中拉回所有现有的id值,而是执行INSERT到“id-generator”表,然后执行SELECT LAST_INSERT_ID()来检索刚刚插入的行的id,将使用它作为“生成”id值。

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


如果需要伪随机性(颤抖),我可能只是尝试INSERT作为一种方法来确定密钥是否存在。如果插入因重复键而失败,我将再次尝试使用不同的id值。

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


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步。

© www.soinside.com 2019 - 2024. All rights reserved.