SQL Server Search Собственные имена Полнотекстовый индекс против LIKE + SOUNDEX - PullRequest
5 голосов
/ 01 июня 2010

У меня есть база данных имен людей, которая имеет (в настоящее время) 35 миллионов строк. Мне нужно знать, что является лучшим методом для быстрого поиска этих имен. Текущая система (не спроектированная мной) просто индексирует столбцы с именами и фамилиями и использует запросы "LIKE" с дополнительной опцией использования SOUNDEX (хотя я не уверен, что это на самом деле часто используется). Производительность всегда была проблемой для этой системы, и поэтому в настоящее время поиск ограничен 200 результатами (что все еще занимает слишком много времени для запуска). Итак, у меня есть несколько вопросов:

  1. Хорошо ли работает полнотекстовый индекс для имен собственных?
  2. Если так, каков наилучший способ запроса имен? (СОДЕРЖИТ, FREETEXT и т. Д.)
  3. Есть ли какая-нибудь другая система (например, Lucene.net), которая была бы лучше?

Просто для справки, я использую Fluent NHibernate для доступа к данным, поэтому методы, которые будут работать с этим, будут предпочтительнее. Я использую SQL Server 2008 в настоящее время.

РЕДАКТИРОВАТЬ Я хочу добавить, что я очень заинтересован в решениях, которые будут иметь дело с такими вещами, как имена с орфографической ошибкой, например 'smythe', 'smith', а также с именами, например 'tomas ',' Томас '.

План запроса

  |--Parallelism(Gather Streams)
       |--Nested Loops(Inner Join, OUTER REFERENCES:([testdb].[dbo].[Test].[Id], [Expr1004]) OPTIMIZED WITH UNORDERED PREFETCH)
            |--Hash Match(Inner Join, HASH:([testdb].[dbo].[Test].[Id])=([testdb].[dbo].[Test].[Id]))
            |    |--Bitmap(HASH:([testdb].[dbo].[Test].[Id]), DEFINE:([Bitmap1003]))
            |    |    |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([testdb].[dbo].[Test].[Id]))
            |    |         |--Index Seek(OBJECT:([testdb].[dbo].[Test].[IX_Test_LastName]), SEEK:([testdb].[dbo].[Test].[LastName] >= 'WHITDþ' AND [testdb].[dbo].[Test].[LastName] < 'WHITF'),  WHERE:([testdb].[dbo].[Test].[LastName] like 'WHITE%') ORDERED FORWARD)
            |    |--Parallelism(Repartition Streams, Hash Partitioning, PARTITION COLUMNS:([testdb].[dbo].[Test].[Id]))
            |         |--Index Seek(OBJECT:([testdb].[dbo].[Test].[IX_Test_FirstName]), SEEK:([testdb].[dbo].[Test].[FirstName] >= 'THOMARþ' AND [testdb].[dbo].[Test].[FirstName] < 'THOMAT'),  WHERE:([testdb].[dbo].[Test].[FirstName] like 'THOMAS%' AND PROBE([Bitmap1003],[testdb].[dbo].[Test].[Id],N'[IN ROW]')) ORDERED FORWARD)
            |--Clustered Index Seek(OBJECT:([testdb].[dbo].[Test].[PK__TEST__3214EC073B95D2F1]), SEEK:([testdb].[dbo].[Test].[Id]=[testdb].[dbo].[Test].[Id]) LOOKUP ORDERED FORWARD)

SQL для выше:

SELECT * FROM testdb.dbo.Test WHERE LastName LIKE 'WHITE%' AND FirstName LIKE 'THOMAS%'

Основываясь на совете Митча, я создал такой индекс:

CREATE INDEX IX_Test_Name_DOB
ON Test (LastName ASC, FirstName ASC, BirthDate ASC)
INCLUDE (and here I list the other columns)

Мой поиск теперь невероятно быстр для моего обычного поиска (последний, первый и дата рождения).

Ответы [ 3 ]

5 голосов
/ 01 июня 2010

Зависит от того, как выглядят ваши запросы LIKE.

Если вы ищете LIKE '%abc%', то индекс не может быть использован, тогда как при поиске LIKE 'abc%' можно использовать индекс. Кроме того, если индекс (-ы) по имени и фамилии не «покрывают» отправленный запрос, то будет выполнен поиск ключей (поиск по закладкам), что значительно повлияет на производительность.

Регулярно ли перестраиваются ваши индексы?

У вас есть пример плана запроса?

Обновление : индекс покрытия для запроса - это индекс, который может использоваться для выполнения критериев WHERE, а также содержит все столбцы, необходимые для удовлетворения остальной части запроса, например список столбцов SELECT.

Использование покрывающих индексов для повышения производительности запросов

Обновление : Даже если вы создадите составной индекс в (Lastname, Firstname) (поскольку фамилия должна быть более избирательной), поиск всех остальных столбцов (список столбцов '*) все равно будет необходим в таблицы кластерный индекс.

1 голос
/ 01 июня 2010

Мне не очень нравится Soundex. Я думаю, что новые итерации алгоритма лучше, но вы хэшируете каждое слово в английском языке до довольно маленького хэша. Это имеет тенденцию генерировать тонну ложных совпадений с течением времени. Я читал этот метафон, и его преемник - двойной метафон лучше, но у меня нет прямого опыта с ними.

Охват Митча like довольно тщательный, поэтому я не собираюсь повторять его.

0 голосов
/ 01 июня 2010

Если вы создадите индекс по столбцам имени и фамилии, то поиск с точным соответствием и поиском по префиксу с помощью LIKE станет невероятно быстрым.

MySQL , «Индекс также можно использовать для сравнений LIKE, если аргумент LIKE является константной строкой, которая не начинается с символа подстановки.» Я думаю, что в MS SQL есть похожее правило , но проверьте документацию MS SQL, чтобы быть уверенным.)

Чтобы ускорить поиск SoundEx, сохраните версию SoundEx для имени и фамилии новых столбцов и создайте индексы для этих столбцов.

...