Плюсы и минусы использования хэша MD5 в качестве первичного ключа и использования идентификатора int в качестве первичного ключа в SQL Server

у меня есть приложение для работы с файлом и его фрагментации на несколько сегментов, а затем сохраните результат в базе данных sql server. Существует много дублированных файлов (возможно, с другим путем к файлу), поэтому сначала я просматриваю все эти файлы и вычисляю хэш Md5 для каждого файла и отмечаю дублированный файл с помощью столбца [Duplicated].

затем каждый день я буду запускать это приложение и сохранять результаты в таблицу [Result]. Схемы БД в ниже:

    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])
    )

и у меня есть требование присоединиться к этим 2 таблицам на FileMd5Hash.

поскольку количество строк [Result] очень велико, я хотел бы добавить столбец идентификатора int, чтобы соединить их с таблицами, как показано ниже:

    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])
    )

Итак, каковы плюсы и минусы этих 2 способов?

3 ответов


ключ int проще реализовать и проще использовать и понимать. Он также меньше (4 байта против 16 байтов), поэтому индексы будут соответствовать примерно удвоенному количеству записей на странице ввода-вывода, что означает лучшую производительность. Строки таблицы тоже будут меньше (ОК, не намного меньше), поэтому вы снова поместите больше строк на страницу = меньше ввода-вывода.

хэш всегда может вызвать коллизии. Хотя и чрезвычайно редко, тем не менее, как проблема рождения показывает, столкновения становятся все более и более вероятно, по мере увеличения количества записей. Количество элементов, необходимых для 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 последовательный первичные ключи для таблиц. Все остальные.


используйте ints для первичных ключей, а не хэши. Все предупреждают о хэш-коллизиях, но на практике они не являются большой проблемой; легко проверить наличие коллизий и повторного хэша. Последовательные идентификаторы также могут сталкиваться при слиянии баз данных.

большая проблема с хэшами как ключами заключается в том, что вы не можете изменить свои данные. Если вы попытаетесь, ваш хэш изменится, и все внешние ключи станут недействительными. Вы должны создать столбец" нет, это настоящий хэш " в вашей базе данных, а ваш старый хэш просто становится большой непоследовательные целое.

держу пари, ваш бизнес-аналитик скажет: "мы внедряем червя, чтобы наши записи никогда не менялись". Они окажутся неправы.


вот очень хорошая статья, объясняющая плюсы и минусы использования обоих:

http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

использование хэша MD5 будет похоже на использование GUID для вашего первичного ключа. Хэш-столкновения редки, но случаются, вы можете захотеть справиться с этим.

Я лично пойду с int IDENTITY, но он может отличаться в зависимости от вашей реализации.