使用MD5 Hash作为主键与使用int标识作为SQL Server主键的优缺点

ric*_*cky 12 sql database sql-server hash

我有一个应用程序来处理文件并将其分成多个段,然后将结果保存到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])
    )
Run Code Online (Sandbox Code Playgroud)

我要求在FileMd5Hash上加入这两个表.

由于[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])
    )
Run Code Online (Sandbox Code Playgroud)

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

Boh*_*ian 13

int键更易于实现,更易于使用和理解.它也更小(4个字节对16个字节),因此索引大约是每个IO页面条目数的两倍,这意味着更好的性能.表行也会更小(好,不会小很多),所以再次,你每页可以容纳更多的行=更少的IO.

哈希总是会产生碰撞.虽然极为罕见,但正如生日问题所示,随着记录数增加,碰撞变得越来越可能.与各种比特长度哈希碰撞的几率为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
Run Code Online (Sandbox Code Playgroud)

还有一个问题是必须传递非ascii字节 - 更难调试,通过线路发送等.

int对表使用顺序主键.其他人都这样做.


Dou*_*rch 8

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

散列作为键的一个大问题是你不能改变你的数据。如果您尝试,您的散列值将更改并且所有外键都将无效。你必须在你的数据库中创建一个“不,这是真正的散列”列,你的旧散列就变成了一个大的非连续整数。

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

  • 外键如何变得无效。如果原始表中的哈希值发生变化 - 那些使用哈希列作为外键的表的值将分别发生变化吗? (2认同)