【问题标题】:Generating unique account numbers - recursive call生成唯一帐号 - 递归调用
【发布时间】:2008-09-19 00:59:11
【问题描述】:

您好,我需要生成 9 位唯一帐号。这是我的伪代码:

function generateAccNo()

    generate an account number between 100,000,000 and 999,999,999

    if the account number already exists in the DB 
        call generateAccNo()    /* recursive call */
    else
        return new accout number
    end if

end function

该函数似乎运行良好,但是我有点担心递归调用。

这会导致任何内存泄漏(Apache 下的 PHP 5)吗?

这是解决此问题的可接受方法吗?

感谢您的意见。

【问题讨论】:

    标签: unique records


    【解决方案1】:

    您意识到这很可能导致堆栈溢出,对吧?随着客户数量的增加,找不到可接受的帐号的概率也会增加。

    另外,你为什么不能只做连续的帐号,每次都加一?使用这种方法,您只需要读取数据库中当前的最大 id 并增加它。

    很抱歉这么直率,但您的解决方案是解决问题的糟糕方法。它将使用大量内存(因为堆栈可能无限增长),并且会对数据库进行大量昂贵的调用。

    您真的应该考虑其他方法:
    我强烈建议每次创建客户时都增加客户编号。事实上,如果你正确地设置了你的数据库(在 id 列上自动增加),你甚至不必设置 id。每当您插入新客户时,都会为您设置 ID。

    【讨论】:

    • 但是 stackoverflow 很棒!
    • 这不太可能。这取决于生成的账号的随机性和活跃账号的数量。使用托管代码,您必须递归数千次才能打破堆栈。当非唯一性的概率接近 10,000:1 时,就该担心了。
    • 感谢 Esetban,您对我讲了一些道理,呵呵 :) 我会让 DB 为我创造价值并坚持使用序列号。谢谢
    • @Eli:对不起,我不得不这么直率,但我不能让你按照这里的几个建议你做的事情。很高兴我能帮上忙。
    【解决方案2】:

    我真的不认为它归结为递归与循环,随着数据集的增长以及随机数生成未正确实现,两者都容易出现问题。想到了两个想法:

    。图形用户名

    如果需要一个真正唯一的 ID 并尽可能少地努力,请考虑使用 GUID,如果不能在代码中创建一个,您的数据库很可能能够在插入时为您分配。尽管它不是非常用户友好,但它保证是唯一的。但是,结合数据库在插入时生成的顺序 AccountRecordId,您将拥有可靠的组合

    。复合键:随机+顺序

    解决所有需求的一种方法,虽然表面上感觉有点笨拙,但是从 5 位(或更多)的顺序 db 密钥创建一个复合帐号,然后再创建一个 5 位随机数。如果随机数是重复的,那也没关系,因为顺序 id 可以保证整个帐号的唯一性

    【讨论】:

      【解决方案3】:

      这里不需要使用递归调用。在函数测试中运行一个简单的while循环,以不存在作为条件,例如

      function generateAccNo()
      
          generate an account number between 100,000,000 and 999,999,999
      
          while ( the account number already exists in the DB ) {
               generate new account number;
          }
          return new account number
      
      end function
      

      但是,如果此代码用于玩具以外的任何东西,则随机生成和测试是生成唯一帐号的次优方法。

      【讨论】:

      • 什么!?!您想仅仅为了创建一个帐号而进行 899,999,999 次 db 点击吗?对我来说似乎是个坏方法。
      • 当我们这样做的时候,我们通常使用数据库的一些特性来产生值,所以它是一个查询而不是 O(n)。
      • @Eli:是的,看看我在这个下面的答案。
      • 在我看来,这个解决方案并不好,堆栈溢出问题不是一个严重的问题。此外,哈希表和字典也有同样的问题,也许您也应该研究这些解决方案(提示,这些解决方案可能看起来很熟悉)。
      • 我坦率地同意,使用碰撞测试进行随机生成是一个坏主意——请参阅我的后记脚本——但独立于不必要的递归这个坏主意,这是一个坏主意。
      【解决方案4】:

      看起来不错,但我认为你需要某种死亡条件,在你放弃之前你要让它运行多少次?

      我知道这在巨大的数字范围内似乎不太可能,但可能会出现问题,只会让你回到上一个电话,这会再次自我调用,令人作呕。

      【讨论】:

        【解决方案5】:

        按顺序生成帐号存在安全风险 - 您应该找到其他算法来执行此操作。

        【讨论】:

        • 仅当您在使用它们时不对其进行哈希处理。
        【解决方案6】:

        或者,您可以维护一个单独的表,其中包含一个生成的、已知是唯一的帐号的缓冲区。该表应该有一个自动递增的整数 id。当您想要一个帐号时,只需拉出缓冲区中索引最低的记录并将其从该表中删除即可。有一些定期运行的进程来补充缓冲区并确保它有容量>>正常使用。这样做的好处是最终用户创建帐号所花费的时间基本上是恒定的。

        另外,我应该注意到递归或迭代的处理开销或风险,真正的问题是确定性和重复数据库查询的开销。我喜欢 TheZenker 的随机 + 顺序解决方案。保证生成唯一的 id 而不会增加不必要的开销。

        【讨论】:

        • 很惊讶这没有更多的赞成票。在运行时按需生成帐号不是一个好的计划,无论是否递归。编写一个循环,根据您的帐号模式按顺序生成一百万个数字,将它们打乱、存储,然后收工。
        【解决方案7】:

        你不需要在这里使用递归。一个简单的循环将同样快并且消耗更少的堆栈空间。

        【讨论】:

          【解决方案8】:

          你可以把它放在一个while循环中:

          function generateAccNo()
          
              while (true) {    
          
                generate an account number between 100,000,000 and 999,999,999
          
                if the account number already exists in the DB 
                    /* do nothing */
                else
                    return new accout number
                end if
              }
          
          end function
          

          【讨论】:

            【解决方案9】:

            为什么不:

            lock_db
            do
                account_num <= generate number
            while account_num in db
            
            put row with account_num in db
            
            unlock_db
            

            【讨论】:

              【解决方案10】:

              为什么不让数据库处理这个?在 SQL Server 中,您可以只拥有一个从 100000000 开始的标识列。或者您可以在您拥有的任何数据库中使用 sql。只需获取最大 id 加 1。

              【讨论】:

              • 我想要随机的帐号而不是顺序的。
              猜你喜欢
              • 1970-01-01
              • 2011-04-25
              • 2015-12-29
              • 1970-01-01
              • 2012-11-04
              • 1970-01-01
              • 1970-01-01
              • 2011-05-21
              • 1970-01-01
              相关资源
              最近更新 更多