生成简短的唯一标识符

时间:2016-04-03 23:11:37

标签: c# .net guid uniqueidentifier identifier

我正在寻找一种能够生成适合两者的标识符的算法,例如在外部使用。 URL以及具有以下要求的持久性:

  • ,就像最大值一样。 8个字符
  • 网址友好,所以没有特殊字符
  • 人性化,例如没有像L / l,0 / O
  • 这样的暧昧字符
  • 增量用于快速索引
  • 随机以防止在不知道算法的情况下猜测(会很好但不重要)
  • 唯一,无需检查数据库

我查看了各种解决方案,但我发现的所有解决方案都有一些重要的权衡。例如:

  • GUID:太长,不是增量
  • GUID base64编码:仍然太长,不是增量
  • GUID ascii85编码:短,非增量,太多不合适的字符
  • GUID编码,如base32,base36:短,但信息丢失
  • 梳子GUID:太长,无论增量
  • 所有其他基于随机的:需要检查数据库的唯一性
  • 基于时间:容易在群集或多线程环境中发生冲突

修改:为什么这个标题偏离主题?这些要求描述了可以提供许多合法解决方案的特定问题。事实上,这里的一些解决方案非常好,我很难选择一个标记作为答案。

4 个答案:

答案 0 :(得分:5)

如果可能的话,我会保持用户要求(简短,可读)和数据库要求(增量,快速索引)分开。面向用户的需求发生变化。您不希望修改表格,因为明天您决定更改面向用户ID的长度或其他细节。

一种方法是使用用户友好的字符生成您的ID,例如
23456789ABCDEFGHJKLMNPQRSTUVWXYZ并随便随意。

但是,当插入数据库时​​,不要将该值作为它引用的记录的主键,甚至将其存储在该表中。使用标识主键将其插入自己的表中,然后将intbigint键存储到您的记录中。

这样您的主表可以拥有增量主键。如果您需要通过其友好的"来引用记录。然后你加入你的友好身份证表。

我的猜测是,如果您生成足够多的这些ID,而您又关注索引性能,那么人类用户检索这些值的速度将会低很多。因此,友好ID表中随机值的稍微慢一点的查找不会成为问题。

答案 1 :(得分:1)

以下使用已知唯一的ID(因为它来自关系数据库中的唯一ID列)和随机的字母和数字序列来生成令牌:

public static string GenerateAccessToken(string uniqueId) // generates a unique, random, and alphanumeric token
{
    const string availableChars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    using (var generator = new RNGCryptoServiceProvider())
    {
        var bytes = new byte[16];
        generator.GetBytes(bytes);
        var chars = bytes.Select(b => availableChars[b % availableChars.Length]);
        var token = new string(chars.ToArray());
        return uniqueId + token;
    }
}

保证令牌既是唯一的又是随机的(或者至少是"伪随机")。您可以通过更改bytes的长度来操纵长度。

避免混淆" 0"和" O"或" l"和" 1",您可以从availableChars删除这些字符。

修改

我刚刚意识到这并没有通过"没有数据库检查"要求,虽然当我使用这样的代码时,我总是已经在内存中有一个我知道包含唯一ID的实体,所以我希望这同样适用于你的情况。我不认为可以完全满足您的所有要求,所以我希望这仍然是属性的良好平衡。

答案 2 :(得分:1)

您是否尝试过提示

Proquint是一个PRO-nouncable QUINT-uplet,交替明确的辅音和元音,例如:" lusab"。

我认为他们几乎满足了你的所有要求。

查看提案herehere是C和Java中的官方实现。

我已经在.NET的端口上工作,您可以将其下载为Proquint.NET

答案 3 :(得分:0)

我之前实施的一个简单的解决方案并不能满足您的所有约束条件,但如果您对问题的看法略有不同,则可能会被接受。

首先,我使用了一个函数来篡改数据库ID func(id) => yfunc(y) => id。 (我使用了Feistel cipherhere是实现这样一个函数的一个例子。)其次,将obfusticated id转换为base 62,使其变短并且对url友好。 (您可以使用较小的字符集来实现人性化)这将创建从数据库ID到字符串标识符的一对一映射。在我的实现中,1,2相应地映射到2PawdM,5eeGE8,我可以从字符串2PawdM和5eeGE8获得数据库ID 1,2。当您使用不同的obfustication函数时,映射可能完全不同。

使用此解决方案,标识符本身不是增量,但是,因为标识符直接映射到数据库ID,所以您可以计算相应的数据库ID,并直接在id列上执行任何数据库查询。您不需要生成字符串标识符并将其存储到数据库,当您使用自动递增的id列存储记录时,数据库本身可以保证唯一性。