使用字符串的哈希创建 Guid

Creating Guid using a hash of a string

我正在考虑在 noSQL 数据库中使用 Guid 作为主键,这是三个不同属性的组合(这可能是个坏主意)。这三个属性是;两个整数和一个 DateTime - 它们在组合时是唯一的。我使用 Guid 的原因是因为相同结构的预先存在的数据使用 Guid 而不是这些属性来查找数据。

如果我将它们转换为字符串并连接它们。然后我转换为 byte[] 并创建一个 Guid。发生碰撞的可能性有多大?我假设散列将是这里的问题?如果我使用 MD5 等弱 16 字节哈希算法,如果属性不同,两个 guid 匹配(冲突)的机会是多少?例如整数和日期时间?如果我使用像 SHA256 这样的散列算法并且只使用前 16 个字节而不是 MD5,会发生什么情况?碰撞几率还是一样吗?

否则,如果需要,我还有其他选择,例如二次查找,但这会使写入、读取和成本加倍。

示例:

        public static Guid GenerateId(int locationId, int orderNumber, DateTime orderDate)
    {
        var combined = $"{locationId}{orderNumber}{orderDate.ToString("d", CultureInfo.InvariantCulture)}";
        using (MD5 md5 = MD5.Create())
        {
            byte[] hash = md5.ComputeHash(Encoding.Default.GetBytes(combined));
            return new Guid(hash);
        }
    }

为什么要散列?如果您完全确定这三个参数的组合始终是唯一的,那么您就拥有了创建唯一 GUID 所需的所有数据。 DateTime 是 8 个字节长,int 是 4 个字节长,所以您的数据是 16 个字节长,这就是 GUID 的确切大小。您可以使用 BitConverter 获取这些值的字节并使用采用 16 字节数组的 GUID 构造函数:

DateTime firstValue = DateTime.Now; //Or whatever it is
int secondValue = 33; //whatever
int thirdValue = 44;  //whatever

List<byte> tempBuffer = new List<byte>();

tempBuffer.AddRange(BitConverter.GetBytes(firstValue.ToBinary())); //Needs to convert to long first with ToBinary
tempBuffer.AddRange(BitConverter.GetBytes(secondValue));
tempBuffer.AddRange(BitConverter.GetBytes(thirdValue));

Guid id = new Guid(tempBuffer.ToArray());