2012-03-11 137 views
7

我目前正在开发注册系统原型。它非常简单,基本上只是一个写入MongoDB的.NET表单。针对数据库条目的高效唯一密钥生成

我卡与什么是产生每个用户的唯一ID /密钥的有效方式。这些ID必须是人性化的,例如7个字符长的字母数字字符串,例如A1B2C3X。

我到目前为止看到只使用一个简单的函数来生成一个随机字符串,然后检查数据库,看看它是否是唯一的(如果不是重复,直到你找到一个独一无二的)的解决方案。随着数据库条目数量的增长,这当然会越来越计算成本。

我的想法是预先计算的唯一ID设置和存储在另一个数据库。然后,当我需要向用户数据库中添加一个新条目时,我可以从我的id数据库中“持续”弹出一个id,并知道它不存在于用户数据库中,而无需搜索它。

我确定有人必须做过这样的事情。有没有更好的办法?我不知道我为什么这么挣扎。非常感谢您的意见。

+2

由MongoDB驱动程序提供的ObjectId是否对您的用例太不友好? – 2012-03-11 12:39:21

+0

我正在建议@EkinKoc的建议(如果你有40个字符,那么这就是要走的路)。但是,如果您只需要7个字符,那么您所概述的方法应该比使用单独的数据库密钥存储区弹出值更便宜*,更简单,并且更少出错。在随机的7个字符的字母数字字符串上碰撞的几率几乎为零。这是一个罕见的边缘情况,你不应该优化。 (无论如何用户创建是很少见的,数据库唯一性检查对于相对较少的进程来说足够快)。 – 2012-03-11 12:42:37

+0

@ BenLee:碰撞的概率随着比例的变化而变化:) – 2012-03-11 12:44:06

回答

11

生成应用程序中的一个随机字符串和检查,如果它独特的是不是一个坏的解决方案。不要担心它效率低下,这不是 - 也绝不会与其他方法相比较。它肯定会比运行db.user.count()或保留具有预先计算的ID的单独表格更快。你只需要做对。

首先,创建新用户的频率如何?可能与其他事情不太经常比较,所以整个效率讨论实际上是没有意义的。其次,A-Z有7个字符,0-9的范围是36^7或者大约780亿。至少可以说,在你开始看到碰撞之前还需要一段时间。

如果你只是像这样做,它不会产生任何性能损失,除非有一个碰撞(这是非常不可能的):

  • 生成一个唯一的用户ID
  • 插入用户对象,使用用户ID为_id
  • 检查重复键错误的值(如何做到这一点取决于语言和驱动程序,但可能涉及运行​​命令)。
  • 在重复键错误从头再来通过生成新的用户ID

这样只会出现在碰撞的情况下,额外的工作(我真的,真的想强调的是多么的不可能会是)。

还有另一种生成唯一用户标识的方法:取当前的UNIX时间戳(第二个),追加主机名和进程标识的散列,最后是计数器的当前值。实际上,Mongo的ObjectId是如何生成的,并且确保您可以每个进程每秒生成多个对象,作为您计数器的最大值(在Mongo中为3个字节,即1600万)。请参阅ObjectId上的文档,如果您对这些细节感兴趣:http://www.mongodb.org/display/DOCS/Object+IDs

它具有您的用户ID自然按照创建顺序排序的属性,但它的长度为12个字节,比7个字符长一些,不幸。您可以使用相同的方法并跳过主机名/ pid,并将计数器(如果您愿意,也可以是一个随机数)缩短为两个字节,那么您将减少到6个字节,这可能会被压缩到大约9字母AZ,0-9。

+0

感谢您的详细解答。你的解决方案听起来是最简单的。现在插入使用_id然后检查一个重复键错误,而不是手动检查collison(在应用程序中),然后插入它是有意义的。我认为这种微妙的差异是让我对解决方案的效率感到担忧,因为只要你做得对,你正确地指出这是不合理的。再次感谢。 – 2012-03-11 14:28:29