【问题标题】:Pros and cons of using MD5 Hash as the primary key vs. use a int identity as the primary key in SQL Server在 SQL Server 中使用 MD5 哈希作为主键与使用 int 标识作为主键的优缺点
【发布时间】:2019-08-02 22:56:15
【问题描述】:

我有一个应用程序来处理一个文件并将其分成多个段,然后将结果保存到 sql server 数据库中。有很多重复文件(可能有不同的文件路径),所以首先我遍历所有这些文件并计算每个文件的 Md5 哈希,并使用 [Duplicated] 列标记重复文件。

然后,我每天都会运行这个应用程序并将结果保存到 [Result] 表中。 db架构如下:

    CREATE TABLE [dbo].[FilePath]
    (
        [FilePath] NVARCHAR(256) NOT NULL PRIMARY KEY,
        [FileMd5Hash] binay(16) NOT NULL,
        [Duplicated] BIT NOT NULL DEFAULT 0, 
        [LastRunBuild] NVARCHAR(30) NOT NULL DEFAULT 0
    )

    CREATE TABLE [dbo].[Result]
    (
        [Build] NVARCHAR(30) NOT NULL,
        [FileMd5Hash] binay(16) NOT NULL , 
        [SegmentId] INT NOT NULL,
        [SegmentContent] text NOT NULL 
        PRIMARY KEY ([FileMd5Hash], [Build], [SegmentId])
    )

我需要在 FileMd5Hash 上加入这 2 个表。

由于 [Result] 的行数非常多,我想添加一个 int Identity 列来将这些列加入到表中,如下所示:

    CREATE TABLE [dbo].[FilePath]
    (
        [FilePath] NVARCHAR(256) NOT NULL PRIMARY KEY,
        [FileMd5Hash] binay(16) NOT NULL,
        **[Id] INT NOT NULL IDENTITY,**
        [Duplicated] BIT NOT NULL DEFAULT 0, 
        [LastRunBuild] NVARCHAR(30) NOT NULL DEFAULT 0
    )

    CREATE TABLE [dbo].[Result]
    (
        [Build] NVARCHAR(30) NOT NULL,
        **[Id] INT NOT NULL,**  
        [SegmentId] INT NOT NULL,
        [SegmentContent] text NOT NULL 
        PRIMARY KEY ([FileMd5Hash], [Build], [SegmentId])
    )

那么这两种方式的优缺点是什么?

【问题讨论】:

  • 请注意,MD5 算法可以为完全不同的数据产生重复值。检查维基百科,它有更多的细节。我认为使用int id 更好,因为它会更有效地被索引
  • 这里没有足够的信息来了解您要做什么以及为什么您可能需要一个身份列。

标签: sql sql-server database hash


【解决方案1】:

int 键更易于实现,更易于使用和理解。它也更小(4 字节对 16 字节),因此索引将适合每个 IO 页面的条目数的两倍左右,这意味着更好的性能。表格的行也会更小(好吧,不会小很多),所以每页可以容纳更多的行 = 更少的 IO。

哈希总是会产生冲突。尽管极为罕见,但正如birthday problem 所示,随着记录数的增加,冲突变得越来越可能。与各种位长哈希发生冲突的概率为 50% 所需的项目数如下:

Hash length (bits)   Item count for 50% chance of collision
                32   77000
                64   5.1 billion
               128   22 billion billion
               256   400 billion billion billion billion

还有必须传递非 ascii 字节的问题 - 更难调试、通过线路发送等。

为您的表使用int 顺序主键。其他人都这样做。

【讨论】:

  • Calculation verified。概率约为 0.44,32 位和 70,000 个项目。 140,000,几乎是 90%。这是否意味着,如果唯一性至关重要,那么对于该项目顺序实际上是无用的。
  • @usr 你在说什么?我是说使用 int 顺序(代理)键和 not 使用散列作为键。这是与密码学或安全性无关的实际问题。
  • 这是一个非常实用的解决方案!点赞!
【解决方案2】:

对主键使用整数,而不是哈希。每个人都会警告哈希冲突,但实际上它们并不是什么大问题;检查冲突和重新散列很容易。如果合并数据库,顺序 ID 也可能发生冲突。

哈希作为键的最大问题是您无法更改数据。如果你尝试,你的哈希值会改变,所有的外键都会失效。您必须在数据库中创建一个“不,这是真正的哈希”列,而您的旧哈希只是变成一个大的非序列整数。

我敢打赌,您的业务分析师会说“我们实施了 WORM,因此我们的记录永远不会改变”。他们将被证明是错误的。

【讨论】:

  • 外键如何失效。如果原始表中的哈希发生变化 - 那些使用哈希列作为外键的表将分别改变它们的值?
【解决方案3】:

这是一篇很好的文章,解释了同时使用两者的优缺点:

https://web.archive.org/web/20140618031501/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

使用 MD5 散列就像使用 GUID 作为主键一样。哈希冲突很少见,但确实会发生,您可能需要处理它。

我个人会选择 INT IDENTITY,但它可能会根据您的实施而有所不同。

【讨论】:

  • archive.org 链接应该是标准做法(如果有)。谢谢。
猜你喜欢
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 2011-07-02
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-15
相关资源
最近更新 更多