Проверка дубликатов на SQL сервере - один столбец или много? - PullRequest
1 голос
/ 02 декабря 2009

В моей работе нам приходится многократно проверять имена и адреса. В прошлом я всегда просто создавал индекс по соответствующим столбцам и запрашивал эти столбцы (имя, фамилия, адрес, город, штат, почтовый индекс и т. Д.) Напрямую. В последнее время мне стало интересно, имеет ли смысл хешировать эти значения перед вставкой и индексировать только хеш для сравнения. Предполагая, что я использую что-то вроде SHA-256 для хэша, мне не нужно беспокоиться о коллизиях (мой набор данных не такой большой), и мой размер индекса будет составлять всего 32 байта на запись или 64 байта, если я сохраню это как строка, где индексом данных NACSZ может быть 200-300 байт.

Это хорошая идея? Я глуп, что не учел это раньше? Есть ли веская причина не делать этого? И что касается стиля, какое название будет хорошим для этого столбца?

Ответы [ 4 ]

3 голосов
/ 02 декабря 2009

Хорошая идея, конечно - ты глуп, что не учел это раньше, определенно нет. Я также не могу придумать какой-либо веской причины не делать этого, особенно если ваш набор данных не такой большой. Конечно, это может заставить кого-то задуматься, есть ли для этого веская причина (т. Е. Если ваш набор данных не такой большой, почему вы заботитесь о том, чтобы индекс NACSZ имел размер 200–300 байт).

Как всегда, есть лоты вещей, которые необходимо учитывать, чтобы определить, что лучше всего подходит для вашего сценария (например, шаблоны использования, избирательность, отношения чтения и записи и т. Д.), поэтому любому человеку трудно дать какой-либо окончательный ответ на что-то вроде этого.

Одна вещь, которую следует учитывать, учитывая, что вы используете Sql Server (не уверен, какую версию, но я предполагаю 2k5 или более позднюю) - хотя есть встроенная функция для генерации хэшей SHA / MDx, его не так просто использовать, как аналогичную функцию хеширования контрольной суммы . Использование функции hashbytes требует, чтобы вы строили входную строку для явного хэширования, тогда как функция контрольной суммы может просто взять действительный список столбцов - простой пример показывает различия:

-- CHECKSUM - easily hash an entire record over a set, regardless of column datatypes
select  checksum(c.*)
from    sys.columns c

-- CHECKSUM - easily hash a subset of columns for a record over a set, regardless of column datatypes
select  checksum(c.name, c.object_id, c.column_id)
from    sys.columns c

-- HASHBYTES - this DOES NOT work
select  hashbytes('MD5', c.*)
from    sys.columns c

-- HASHBYTES - this DOES NOT work either
select  hashbytes('MD5', c.name, c.object_id, c.column_id)
from    sys.columns c

-- HASHBYTES - you have to explicitly build the string, casting to valid character-based datatypes
select  hashbytes('MD5', a.name + cast(a.object_id as varchar(50)) + cast(a.column_id as varchar(50)))
from    sys.columns a

Простота использования также очень удобна при выполнении объединений / союзов / и т.д. в разных таблицах / наборах данных.

Очевидно, что хэш контрольной суммы является всего лишь 32-битным алгоритмом и, скорее всего, приведет к коллизиям, однако это может не иметь никакого значения, если вашей основной целью является создание поискового индекса для повышения производительности, а затем выполнение дополнительных вторичных проверок. Например, если вы создадите столбец хеш-проверки контрольной суммы () в таблице и индексируете только этот столбец, вы получите небольшой индекс, который все еще можно будет использовать для поиска, а затем выполнять вторичные / остаточные сравнения значений NACSZ в небольшое подмножество столбцов, которые соответствуют контрольной сумме (). Запрос в этом сценарии может выглядеть следующим образом:

declare @hash int

select  @hash = checksum(@first_name,@last_name,@address,@city,@state,@zip)

select  t.firstname, t.lastname, t.address, t.city, t.state, t.zip
from    TableName t
where   t.record_hash = @hash
and     t.firstname = @first_name
and     t.lastname = @last_name
and     t.address = @address
and     t.city = @city
and     t.state = @state
and     t.zip = @zip

Оптимизатор будет искать в основном по хеш-индексу и выполнять остаточную проверку значений NACSZ для подмножества записей, соответствующих хеш-значению.

Естественно, если вы собираетесь сгенерировать хэш в коде приложения, это, скорее всего, менее проблемная проблема.

Что касается соглашений / стиля именования, не могу сказать, поскольку я когда-либо слышал о чем-то конкретном для этого типа использования, однако для тех, которые я видел / использовал, имена столбцов обычно включают обозначение 'hash' и тип хэша - например, «record_checksum_hash» или «record_sha1_hash» или «md5_hash».

1 голос
/ 02 декабря 2009

Это неплохая идея, но если ваш набор данных невелик, я не уверен, что вы получите что-то осязаемое, кроме некоторых дублирующих полей (хэшей уже существующих полей).Вы планируете сделать это, потому что поиск обманщика идет медленно или просто из-за желания оптимизировать?

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

0 голосов
/ 03 декабря 2009

Большинство хэшей не обнаруживают дубликаты в тех случаях, когда буквы и регистр отличаются. Пожалуйста, сравните:

select checksum('Cafe'), checksum('cafe'), checksum('Café'), checksum(' Cafe');
select hashbytes('SHA1', 'Cafe'), hashbytes('SHA1', 'cafe'), hashbytes('SHA1', 'Café'), hashbytes('SHA1', ' Cafe');
0 голосов
/ 03 декабря 2009

Если ваши сравнения ищут точное совпадение, и если сравнения происходят часто (или если скорость сравнения важнее скорости вставки), то я думаю, что вычисление хэша было бы очень хорошей идеей. Мало того, что индекс будет меньше, но сравнение для каждой строки будет быстрее. На самом деле, вы должны быть в состоянии избежать неприятностей с SHA-1, который составляет всего 160 бит, вместо SHA-256. Дополнительные биты помогают с криптологической точки зрения; они действительно не улучшают уникальность.

Конечно, убедитесь, что канонизировали ваши данные перед вычислением хэша, сравнения "LIKE" не работают с хэшем, как со строками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...