2017-01-26 24 views
9

У меня есть таблица в базе данных SQL Server с полем адреса (например, Farnham Road, Guildford, Surrey, GU2XFF), который я хочу искать с подстановочным знаком до и после строки поиска ,Оптимизация выражений LIKE, которые начинаются с подстановочных знаков

SELECT * 
FROM Table 
WHERE Address_Field LIKE '%nham%' 

У меня есть около 2 миллионов записей в этой таблице, и я нахожу, что запросы занять от 5-10s, который не является идеальным. Я считаю, что это связано с предыдущим шаблоном.

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

Использование полного поиска текста и CONTAINS невозможно, потому что я хочу искать последние части слов (я знаю, что вы могли бы заменить строку поиска для Guil * в нижнем запросе, и это вернет результаты). Безусловно, следующие возвраты нет.

SELECT * 
FROM Table 
WHERE CONTAINS(Address_Field, '"nham"') 

Есть ли способ оптимизировать запросы с помощью предыдущих подстановочных знаков?

+2

Насколько я знаю, SQL Server не имеет встроенного типа индекса, который делает то, что вы хотите (Postgres). Есть способы делать то, что вы хотите, но они требуют большой работы. –

+1

Вы правы в том, что индексы не смогли бы найти этого, но даже сканирование индекса с помощью ключевых поисков может быть быстрее, чем сканирование таблицы, если это то, что он делает сейчас. Тебе придется протестировать его и посмотреть. – SqlZim

+1

Точка уточнения: вы можете искать части слов с полнотекстовыми индексами, но это должна быть первая часть слова. Используя ваш пример строки, вы можете успешно использовать полнотекстовый индекс, ища «Guil», но вы правильно говорите, что это не будет работать для «nham». – dfundako

ответ

4

Это одно (не рекомендуется).

Создать таблицу AddressSubstrings. Эта таблица будет иметь несколько строк на адрес и первичный ключ table.

Когда вы вставляете адрес в table, вставьте подстроки, начиная с каждой позиции. Итак, если вы хотите вставить 'ABCD', то вы бы вставить:

  • ABCD
  • BCD
  • кд
  • d

вместе с уникальным идентификатором строки в Таблица. (Это можно сделать с помощью триггера.)

Создать индекс на AddressSubstrings(AddressSubstring).

Тогда вы можете фраза ваш запрос как:

SELECT * 
FROM Table t JOIN 
    AddressSubstrings ads 
    ON t.table_id = ads.table_id 
WHERE ads.AddressSubstring LIKE 'nham%'; 

Теперь будет соответствующая строка, начиная с nham. Итак, like должен использовать индекс (и работает полный текстовый индекс).

Если вам интересно в править способ справиться с этой проблемой, разумным местом для начала является Postgres documentation. Это использует метод, аналогичный описанному выше, но с использованием n-граммов. Единственная проблема с n-граммами для вашей конкретной проблемы заключается в том, что они требуют повторной записи сравнения, а также изменения хранилища.

1

Не без серьезного усилия по подготовке, hwilson1.

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

С помощью ведущих подстановочных знаков вам не повезло.

Обходной серьезное усилие подготовки, как указано фронт:

Это свелось бы текст поиска функции Vertica, где решается эта проблема. Смотрите здесь:

https://my.vertica.com/docs/8.0.x/HTML/index.htm#Authoring/AdministratorsGuide/Tables/TextSearch/UsingTextSearch.htm

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

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

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

Если ваша входная таблица (только с указанием столбцов, которые имеют значение) заключается в следующем:

id |the_search_col       |other_col 
    42|The Restaurant at the End of the Universe|Arthur Dent 
    43|The Hitch-Hiker's Guide to the Galaxy |Ford Prefect 

Ваша вспомогательный поиск таблица может содержать:

id |seq|search_token 
    42| 1|Restaurant 
    42| 2|End 
    42| 3|Universe 
    43| 1|Hitch-Hiker 
    43| 2|Guide 
    43| 3|Galaxy 

Обычно, вы подавлять типичные «наполнители», такие как статьи, предлоги и апострофы, и разделяться на токены, разделенные пунктуацией и пробелом. Тем не менее, для вашего примера «% nham%» вам, вероятно, нужно поговорить с лингвистом, специализирующимся на английской морфологии, чтобы найти кандидатов на маркеры разделения ....: -]

Вы можете начать с той же методики что я использую, когда я ООН-шарнирный горизонтальный ряд мер без предложения PIVOT, как здесь:

Pivot sql convert rows to columns

Затем, используя комбинацию, вероятно, вложенный, CHARINDEX() и SUBSTRING(), используя индекс вы получаете от CROSS JOIN серию индексных целых чисел, как описано в моем сообщении, предложенном выше, и используйте этот самый индекс в качестве последовательности для вспомогательной таблицы поиска.

Положите индекс на search_token, и у вас будет очень быстрый путь доступа к большой таблице.

не прогулка в парке, я согласен, но многообещающим ...

Счастливая игра -

Marco здравомыслящий

3

Я не могу предложить полное решение этой сложной проблемы.

Но если вы хотите, чтобы создать возможность поиска суффиксов, в котором, например, вы были бы в состоянии найти строку, содержащую HWilson с ilson и строку, содержащую ABC123000654 с 654, вот предложение.

WHERE REVERSE(textcolumn) LIKE REVERSE('ilson') + '%' 

Конечно, это не sargable так, как я написал здесь.Но многие современные СУБД, включая последние версии SQL-сервера, позволяют определять и индексировать вычисленные или виртуальные столбцы.

Я развернул эту технику, в восторге от конечных пользователей, в системе здравоохранения с большим количеством идентификаторов записей, таких как ABC123000654.

 Смежные вопросы

  • Нет связанных вопросов^_^