【问题标题】:Most Efficient Way to... Unique Random String最有效的方法...唯一的随机字符串
【发布时间】:2009-10-03 14:41:08
【问题描述】:

我需要有效地将 5 个字符的 RANDOM 字符串插入数据库,同时还要确保它是唯一的。生成随机字符串不是问题,但目前我正在做的是生成字符串,然后检查数据库是否已经存在......如果存在,我重新开始。

有没有更有效的方法来完成这个过程?

请注意,我不想使用 GUID 或任何超过 5 个字符的东西......我必须坚持使用 5 个字符。

PS:我不认为这有什么区别,但我的字符串都是区分大小写的。

这里是“随机字符串”部分

    Public Function GetRandomNumbers(ByVal numChars As Integer) As String
    Dim chars As String() = { _
     "A", "B", "C", "D", "E", "F", _
     "G", "H", "I", "J", "K", "L", _
     "M", "N", "O", "P", "Q", "R", _
     "S", "T", "U", "V", "W", "X", _
     "Y", "Z", "0", "1", "2", "3", _
     "4", "5", "6", "7", "8", "9", _
     "a", "b", "c", "d", "e", "f", _
     "g", "h", "i", "j", "k", "l", _
     "m", "n", "o", "p", "q", "r", _
     "s", "t", "u", "v", "w", "x", _
     "y", "z"}
    Dim rnd As New Random()
    Dim random As String = String.Empty
    Dim i As Integer = 0
    While i < numChars
        random += chars(rnd.[Next](0, 62))
        System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
    End While
    Return random
End Function

【问题讨论】:

  • 不找人来写我的代码。只是在寻找一个效率概念。

标签: asp.net database random unique


【解决方案1】:

创建一个包含大量 5 个字符的字符串池的表,这些字符串按顺序添加(因此它们是唯一的),并以 GUID 作为其主键。添加一列以指示它们是否被使用。

当您需要一个新号码时,您从池中选择前 1 个,按 guid 排序(因此它变得随机),并将结果设置为“已用”。

【讨论】:

  • 这将创建一个额外的表,但将是唯一的、随机的并使用最可能的值,而无需不断搜索当前值。随着行数的增加,OP的原始解决方案将花费越来越长的时间。
  • 所以我假设在生成初始随机字符串之前会有大量工作。
  • 与其添加一列来表明它们是否被使用,为什么不直接删除它们呢?使查询更快、更容易编写。
  • 我将继续使用它们...它们永不过期。
  • 对于一个以 54 为基数的随机字符串,表大小为 4.59 亿,而您所做的只是将同一个问题从一个表转移到另一个表,除非使用了一个可预测的序列,而不是“随机”。跨度>
【解决方案2】:

您可以生成一个 GUID 并且只使用前 5 个字符吗?

【讨论】:

  • 这只是另一种生成随机字符串的方法,您仍然需要检查重复项。
  • 也是我的第一个想法,尽管他必须为区分大小写的字符串生成 5 个额外的位。
【解决方案3】:

随机性更重要还是唯一性更重要? ——注意我说“更”重要;我知道你需要两者。

如果随机性更重要,那么您将需要某种方法来跟踪历史值。数据库本身(带有适当的索引)将是做到这一点的最佳方式。

如果唯一性更重要,则只需使用计数器并将其填零至五位数。当然,这会将您限制为 100,000 行,因此您可以选择使用计数器和转换为字符空间(例如,1 = "A"、2 = "B"、27 = "AA" 等) .

【讨论】:

  • 这个想法只是为了在我的应用程序中构建一个 Url Shortener。我想要 5 个随机字符,就像 bit.ly 一样。
【解决方案4】:

有一种随机挑选未使用的唯一词的方法,但它可能不会比你现在做的更好。

原则是,您确定未使用的单词的哪些排列,根据有多少未使用的排列生成一个随机数,然后选择那个。

例如,如果您要使用包含三个字符的单词,并且只有字符 0 和 1,则有八种可能的排列。如果您已经使用了“010”和“100”的组合,您会得到如下所示的内容:

PI = 排列索引
UI = 未使用的排列索引

No. PI UI
----------
000 0  0
001 1  1
010 2  -
011 3  2
100 4  -
101 5  3
110 6  4
111 7  5

要选择未使用的排列,您只需生成一个从 0 到 5 的随机数,然后选择相应的排列。

保留所有可能排列的列表当然是不切实际的,因此您需要一个可以从字符串中确定排列索引的函数,以及一个可以从排列索引中确定字符串的函数。

此外,要确定哪些排列未使用,您必须检查哪些排列已使用,因此您仍然需要在某个时候查询该表。

【讨论】:

    【解决方案5】:

    如果您要将字符串插入现有的填充表,那么您将始终需要检查该字符串是否不存在(不必是显式 SELECT)。您可以手动设置它,也可以对列设置 UNIQUE 约束并让数据库执行此操作。因此,如果数据库因为字符串已经存在而返回错误,则生成另一个。

    请注意,如果您有一个空表并想用多个随机字符串填充它,那就是另一个问题了。

    【讨论】:

      【解决方案6】:

      我认为你应该坚持你原来的想法。对索引设置唯一约束并让数据库为您检查/报告欺骗将是相当有效的欺骗检查方法,但这种假设取决于一些未提供的信息,例如行数和遇到具有随机选择数据的欺骗的可能性。

      使用您的参数完全预填充唯一序列池需要 4.59 亿行表。

      您可以使用布隆过滤器将可管理的统计信息加载到数据库或主内存中并避免重复,但根据行数和过滤器配置,当行数占 459 的可观百分比时,这可能会导致过滤器饱和百万限制.. 由于过滤器可以报告误报,因此您应该努力确保您不会陷入系统卡住尝试通过过滤器的排列永远接近的情况。

      【讨论】:

        【解决方案7】:

        你知道你的词应该多长,为什么不采用基于树的方法呢? (我们称之为随机树行走)

        假设你的单词有 n 个字符。生成 S 中所有符号 s 的列表,并将每个符号的计数器和字符串中的可能位置关联起来,本质上是一个维度为 s 乘以 n 的矩阵 M。现在掷骰子并选择第一个字母并查找 M(s,1)。如果 M(s,1) 大于或等于以 s 开头的可能单词的数量,则再次滚动。否则递增 M(s,1)。

        对每个字母 1 到 n 重复此操作。

        在你用完很多单词之前应该很快。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-15
          • 1970-01-01
          • 2018-07-03
          • 2012-12-29
          • 1970-01-01
          • 1970-01-01
          • 2017-06-02
          相关资源
          最近更新 更多