【问题标题】:Check unique random value against database with minimal resource use以最少的资源使用检查数据库的唯一随机值
【发布时间】:2016-06-16 18:39:18
【问题描述】:

这更像是一个最佳实践问题。我正在使用以下参数生成一个随机字符串标识符:

  • 长度:7 个字符
  • 种子:A-Za-z0-9(小写 + 大写字母和数字)

我需要在插入之前检查该字符串是否存在于数据库中。我可以通过两种方式做到这一点:

  1. 运行do...while 循环。在其中,生成一个随机字符串,每次使用COUNT(*) 查询数据库,直到count === 0
  2. 首先使用单个查询从数据库中获取所有现有的唯一字符串,然后运行do...while 循环以生成不在提取数组中的随机字符串。

对我来说很明显,第二种方法在技术上对数据库服务器的资源密集度较低,因为只有一个查询,而不是一遍又一遍地查询。所以我倾向于这种方法,但我看到两个潜在的警告:

大型数据库,以及在获取和插入之间经过的时间。

  • 大型数据库结果:在我需要考虑切换到第一种方法之前,查询结果中可以包含多少行?换句话说,数据库服务器上的大型结果集的压力何时低于运行多个后续查询? 1,000 个结果? 5000? 20,000?

  • 获取和插入之间的时间:如果我使用第二种方法,当两个或多个用户尝试同时运行相同的功能时,我会发现风险。第一个用户的结果集(从数据库中获取的唯一字符串)可能不包括在查询后 2 毫秒刚刚添加的其他用户的唯一字符串。这可能会在数据库中产生重复。

第二种方法在生产中真的可行吗,还是只是一个梦想?

【问题讨论】:

  • 您需要分析两次生成相同随机字符串的可能性。如果它足够小,那么您最好尝试插入它并检查您的查询中是否存在任何违反唯一性约束的错误。

标签: php mysql database unique


【解决方案1】:

第二个选项对我来说似乎不切实际。如果表中只有几行,则发生冲突的风险很低,如果有很多行,则冲突的风险会增加,但在 php 端获取所有行的内存效率不高。

第一个解决方案对我来说似乎更好。

但我认为可以使用第三种选择。在 MySQL 中为您的随机值添加唯一索引。生成一个随机值,然后尝试插入它。如果发生碰撞,请捕获错误。这很有效,因为 MySQL 在索引时快速检查值是否存在。这种方法没有并发问题。

唯一需要注意的是(对于所有方法),当表中的行数很高时,您将很难找到尚未使用的值。为了降低碰撞风险,您可以增加随机值的大小。您还可以创建另一个包含未使用值的表,并在该表的值太少时使用其他算法填充此表。

【讨论】:

  • 您可以使用AZaz09 生成长度为 7 的 3x10^12 个唯一字符串序列。我认为存储空间会在碰撞开始发生之前用完。
  • 如果有 30 亿个唯一的字符串序列并且表中有 300 万行,那么您有 1/1000 的机会发生冲突。在这种情况下,冲突发生。这一切都取决于该表的缩放和实际使用情况(OP 并未说明如何使用)。
  • 300 万 = 10^6 和 10^6 / 10^12 = 1/10^6,这是百万分之一。您预计在 300 万行的表中会发生 3 次冲突。这绝不是高碰撞率。碰撞会发生,但我们需要对实际频率保持现实,并根据实际频率编写代码,而不是引入大量开销来处理一些边缘情况。这是指任何“插入前检查”解决方案。
  • 是的,我的错,十亿只是 10e9,而不是 10e12。在所有情况下,碰撞讨论只是一个旁注。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-19
  • 1970-01-01
  • 2013-11-20
  • 2013-09-03
  • 2019-09-11
  • 2013-06-25
相关资源
最近更新 更多