Индекс SQL Server. Есть ли улучшения для запросов LIKE?

StackOverflow https://stackoverflow.com/questions/803783

  •  03-07-2019
  •  | 
  •  

Вопрос

У нас есть запрос, который выполняется к довольно большой таблице, которая, к сожалению, должна использовать LIKE '%ABC%' в паре полей varchar, чтобы пользователь мог выполнять поиск по части имен и т. д.SQL-сервер 2005

Поможет ли добавление индекса в эти поля varchar с точки зрения производительности выборочных запросов при использовании LIKE или в таких случаях оно в основном игнорирует индексы и выполняет полное сканирование?

Есть ли другие возможные способы повышения производительности при использовании LIKE?

Это было полезно?

Решение

Только если вы добавите полнотекстовый поиск в эти столбцы и используете возможности полнотекстовых запросов SQL Server.

В противном случае нет, индекс не поможет.

Другие советы

Потенциально вы можете увидеть улучшение производительности, добавив индекс(ы), это во многом зависит от особенностей :)

Какую часть общего размера строки составляют предикатные столбцы?Сколько строк вы ожидаете совместить?Вам нужно вернуть все строки, соответствующие предикату, или только первую или n верхних строк?

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

Вот пример, в котором общий размер строки намного превышает размер столбца для поиска:

create table t1 (v1 varchar(100), b1 varbinary(8000))
go
--add 10k rows of filler
insert t1 values ('abc123def', cast(replicate('a', 8000) as varbinary(8000)))
go 10000
--add 1 row to find
insert t1 values ('abc456def', cast(replicate('a', 8000) as varbinary(8000)))
go

set statistics io on 
go
select * from t1 where v1 like '%456%'
--shows 10001 logical reads

--create index that only contains the column(s) to search across
create index t1i1 on t1(v1)
go
select * from t1 where v1 like '%456%'
--or can force to 
--shows 37 logical reads

Если вы посмотрите на фактический план выполнения, вы увидите, что механизм просканировал индекс и выполнил поиск закладок в соответствующей строке.Или вы можете напрямую указать оптимизатору использовать индекс, если он не решил использовать этот план самостоятельно:выберите * из t1 с помощью (index(t1i1)), где v1 типа '%456%'

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

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

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

ХТХ!-Адриан

Единственный другой способ (кроме полнотекстового индексирования) повысить производительность — это использовать «LIKE ABC%» — не добавляйте подстановочные знаки на обоих концах поискового запроса — в этом случае индекс может работать.

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

Марк

Например, «%ABC%» всегда будет выполнять полное сканирование таблицы.Обойти это невозможно.

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

В качестве альтернативы в некоторых обстоятельствах может оказаться целесообразным денормализовать данные и предварительно обработать целевые поля в соответствующие токены, а затем добавить эти возможные условия поиска в отдельную таблицу поиска «один ко многим».Например, если бы мои данные всегда состояли из поля, содержащего шаблон «AAA/BBB/CCC», а мои пользователи выполняли поиск на BBB, то я бы токенизировал их при вставке/обновлении (и удалял при удалении).Это также будет один из тех случаев, когда лучше использовать триггеры, а не код приложения. много предпочтительнее.

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

создать статистику по этому столбцу.sql srever 2005 оптимизировал поиск по строкам, так что вы можете извлечь из этого пользу.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top