Плюсы и минусы использования хэша 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])
)
Итак, каковы плюсы и минусы этих двух способов?
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, но она может отличаться в зависимости от вашей реализации.
Comments