在MySQL中实现ids的线性同余生成器的一种巧妙方法?

时间:2013-06-03 21:59:44

标签: mysql primary-key auto-increment userid

一点介绍:在思考将在URL和其他地方公开的哪种独特ID之后,我选择了线性同余生成器(http://en.wikipedia.org/wiki/Linear_congruential_generator)。 为什么不UUID或自动递增?

  • UUID太长,难以存储在db中(推荐的方法是将它们转换为VARBINARY(16))。
  • Auto_increment公开了新实体的注册和添加顺序,并提供了预测下一个ID的功能。例如,如果一个服务变得流行,用户可以进行多次注册以获得一个好的ID,然后尝试出售这样的帐户,ID会给出某种状态:注册冷却器越早。我宁愿避免这样的事情。

使用LCG,序列是随机的,我可以选择参数,以便可能的值很好地适合特定目的的数据类型。例如,对用户ID使用INT UNSIGNED,并选择参数以给出2 ^ 32的周期。

问题是要生成下一个id,我需要获取最后一个id的值:

nextId = (a * lastId + c) % m
  1. 据我所知,我必须自己设置第一个ID?我选择哪个号码很重要吗?
  2. 生成新ID的简洁方法是什么?也许创建一个表,其中包含每个表的最后生成的ID列表?或者为每个表添加一个auto_increment列以跟踪上次生成的id?如果在很短的时间内有很多注册,如何避免出现问题?
  3. UPDATE1: 我发现了一种使用此处信息的多用户安全方法:http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id

    CREATE TABLE sequences (users INT UNSIGNED NOT NULL, posts BIGINT UNSIGNED NOT NULL);
    INSERT INTO sequences VALUES(123456,123456789);
    

    然后获取新ID:

    UPDATE sequences SET users=LAST_INSERT_ID((a * users + c) % m);
    SELECT LAST_INSERT_ID();
    

1 个答案:

答案 0 :(得分:1)

要在MySQL中可靠地执行此操作,您将需要编写存储过程,并使用包含最新ID的单行表。

您的存储过程需要锁定表,读取最新ID,生成新ID,将其更新到表中,解锁表,然后将新ID返回给调用者。

您还可以使用已生成的ID列表保留多行表。在这种情况下,您的存储过程需要锁定,读取最近生成的 ID,生成一个新ID,将其插入表中,解锁并返回。显然,在这种情况下,您将需要一种可靠的方法来查找最近生成的ID。也许使用自动增量列和ID列可以解决问题。

实现所需内容的另一种方法是编写一个生成多位数随机数的存储过程(我用至少48个二进制数字),然后尝试将其作为表的主键插入。只要插入因密钥冲突而失败,请尝试另一个随机数。这些长随机数比你的LCG序列更难预测。

在开始生产之前,您必须在开发过程中严格按照繁重的多客户端负载测试存储过程。如果你没有充分测试,你抱歉。我根据经验知道这些东西很难做对。

UUID确实有你提到的尺寸劣势。但它有一个非常强大的优势:它已经过彻底的测试。如果选择它,您无需尝试重​​新发明轮子。 (根据我的经验,重新发明轮子,我想出了一些扁平轮胎。)