【问题标题】:MySQL using 'random' number as primary keyMySQL使用“随机”数字作为主键
【发布时间】:2013-10-11 15:48:10
【问题描述】:

我有一个带有自动递增主键的表,但我现在需要更改它,这样主键就不会被键入连续数字的人猜到。为了创建随机主键,我想我将创建一个包含所有 6 位数字的表,这些数字按随机顺序排列,并针对 1 到 n 进行键控。

我的问题是,在不更改所有现有查询的情况下,如何使用在第二个表中相应索引处的自动递增键和 6 位数字之间建立链接?

由于只有一个查询可以插入到该表中,因此我想更改它以使事情变得简单。我想查询第二个表中的下一个数字并将其插入到第一个表的主键列中。我预见的问题是两个查询可能同时访问服务器,并可能从第二个表返回相同的 6 位数字。在 MySQL 中解决这个问题有哪些选择?

【问题讨论】:

标签: php mysql sql


【解决方案1】:

与其做所有这些,为什么不使用 UUID?您可以修改您的表格,将这种类型的列添加到您的表格中,您无需担心生成任何内容或跟踪它。

https://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_uuid

【讨论】:

  • UUID 的问题在于它对用户不友好。主键被用作真人浏览应用程序的一种方式。拥有 40 多个字符的密钥不会为我赢得用户的任何好感。
  • 如果你使用 id 进行导航,你为什么要担心人们猜测它?
  • 简述是让用户创建他们的朋友可以使用 pin 加入的游戏,pin 目前是现有表的主键。现在,简报已更改,通过使其非顺序来减少引脚的猜测。没有什么比使用移动的目标职位更重要了。
【解决方案2】:

感谢您的建议,但没有人真正回答我的问题。

我的引脚表如下所示:

id |  pin   | used
 1   123456    1
 2   258464    0
 3   842364    0

我使用查询来获取下一个图钉:

SELECT id, pin FROM game_pins WHERE used = '0' ORDER BY id LIMIT 1;

然后我将该行更新为SET used = '1'

为了防止两个人获得相同的 pin,我使用 InnoDB 事务,在 CodeIgniter 中我通过将所有内容包装在其中来完成:

$this->db->trans_start();

...

$this->db->trans_complete();

【讨论】:

  • 如果您要求已删除游戏的别针永远不会被重复使用,这个答案比 tometzky 的答案要好。但是,如果这不是必需的,那么您只是在浪费磁盘空间。在生成此表时,您必须使用随机 pin 填充它并避免重复,您可能必须生成多个随机 pin 以找到唯一的 pin,其方式与 tometzky 完全相同。
  • 你说 tometzky 的回答是慢,但是运行时间是预计运行时间 O(1),但是你的回答有 worst case 时间 O(1),这意味着您的算法具有“实时”保证,这是您的算法的另一个积极方面,但是您不太可能需要游戏的这种性能。
【解决方案3】:

放弃这个额外的表,只使用rand() 生成介于 100000 和 999999 之间的随机数。选择这个随机数,直到你发现未使用。看起来您不需要经常这样做,因此不必非常快。但是查询会更快,因为不需要额外的连接。

但请记住,它并不比简单的自动增量更安全 - 用户可以在几个小时内尝试所有 900k 的可能性。

【讨论】:

  • 不幸的是,这需要经常进行,请参阅stackoverflow.com/questions/19322234/… 以获得解释。使用rand() 直到找到一个未被使用的号码会太慢。
  • 这应该不是问题。我只会使用rand(),直到大约 50% 的数字用完,然后我只需在上限中添加一个“9”数字。这样,抽到已用数字X 次的概率将始终小于1/2^X,就像在掷硬币时连续出现X 次。在最坏的情况下,您平均只会尝试两次。
猜你喜欢
  • 2011-10-06
  • 1970-01-01
  • 1970-01-01
  • 2013-12-21
  • 2019-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多