LIKE использует индекс, CHARINDEX нет?


22

Этот вопрос связан с моим старым вопросом . Приведенный ниже запрос занимал от 10 до 15 секунд:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE (Charindex('123456789',CAST([company].dbo.[customer].[Phone no] AS VARCHAR(MAX)))>0) 

В некоторых статьях я видел, что использую CASTи CHARINDEXне получу выгоды от индексации. Есть также некоторые статьи, в которых говорится, что использование LIKE '%abc%'индексации не принесет пользы, в то время как LIKE 'abc%':

http://bytes.com/topic/sql-server/answers/81467-using-charindex-vs-like-where /programming/803783/sql-server-index-any-improvement-for -подобные запросы http://www.sqlservercentral.com/Forums/Topic186262-8-1.aspx#bm186568

В моем случае я могу переписать запрос как:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
FROM [company].dbo.[customer]
WHERE [company].dbo.[customer].[Phone no]  LIKE '%123456789%'

Этот запрос дает тот же результат, что и предыдущий. Я создал некластеризованный индекс для столбца Phone no. Когда я выполняю этот запрос, он запускается всего за 1 секунду . Это огромное изменение по сравнению с 14 секундами ранее.

Какую LIKE '%123456789%'пользу приносит индексация?

Почему в перечисленных статьях говорится, что это не улучшит производительность?

Я пытался переписать запрос для использования CHARINDEX, но производительность все еще медленно. Почему CHARINDEXиндексация не приносит пользы, как кажется, что LIKEзапрос делает?

Запрос с использованием CHARINDEX:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

План выполнения:

введите описание изображения здесь

Запрос с использованием LIKE:

SELECT [customer].[Customer name],[customer].[Sl_No],[customer].[Id]
 FROM [Company].dbo.[customer]
 WHERE[Company].dbo.[customer].[Phone no] LIKE '%9000413237%'

План выполнения:

Как план запроса

Ответы:


28

Как LIKE "% 123456789%" получает выгоду от индексации?

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

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

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

Почему в перечисленных статьях говорится, что это не улучшит производительность?

Для LIKEусловия, которое не начинается с подстановочного знака, SQL Server может выполнить частичное сканирование индекса вместо сканирования всего объекта. Например, LIKE 'A%можно правильно оценить, проверяя только записи индекса >= 'A'и < 'B'(точные граничные значения зависят от параметров сортировки).

Этот тип запроса может использовать возможность поиска индексов b-дерева: мы можем перейти прямо к первой записи, >= 'A'используя b-дерево, а затем сканировать вперед в порядке ключа индекса, пока не достигнем записи, которая не прошла < 'B'тест. Поскольку нам нужно только применить LIKEтест к меньшему количеству строк, производительность, как правило, лучше.

Напротив, LIKE '%Aнельзя превратить в частичное сканирование, потому что мы не знаем, где начинать или заканчивать; любая запись может закончиться 'A', поэтому мы не можем улучшить сканирование всего индекса и тестирование каждой строки в отдельности.

Я пытался переписать запрос для использования CHARINDEX, но производительность все еще медленно. Почему CHARINDEXиндексация не приносит пользы, как, кажется, делает запрос LIKE?

Оптимизатор запросов имеет одинаковый выбор между сканированием таблицы (кластеризованный индекс) и сканированием некластеризованного индекса (с поиском) в обоих случаях.

Выбор делается между двумя на основе оценки стоимости . Случилось так, что SQL Server может произвести разные оценки для двух методов. Для LIKEформы запроса оценка может использовать специальную строковую статистику для получения достаточно точной оценки. CHARINDEX > 0Форма производит оценку , основанную на догадке.

Различных оценок достаточно, чтобы оптимизатор выбрал для сканирования Clustered Index Scan CHARINDEXи NonClustered Index Scan для поиска LIKE. Если вы заставите CHARINDEXзапрос использовать некластеризованный индекс с подсказкой, вы получите тот же план, что и для LIKE, и производительность будет примерно такой же:

SELECT
    [Customer name],
    [Sl_No],
    [Id]
FROM dbo.customer WITH (INDEX (f))
WHERE 
    CHARINDEX('9000413237', [Phone no]) >0;

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

Если вам LIKE %thing%часто приходится искать, вы можете рассмотреть методику, о которой я писал в Trigram Wildcard String Search в SQL Server .


16

SQL Server поддерживает статистику подстрок в строковых столбцах в форме попыток, которые могут использоваться LIKEзапросом, а не - CHARINDEX.

Подробнее об этом см. В разделе « Сводная статистика строк» .

Пара важных предостережений заключается в том, что любое экранирование подстановочных знаков должно выполняться с использованием проприетарной техники квадратных скобок, а не ESCAPEключевого слова, и что для строк длиной более 80 символов используются только первые и последние 40 символов.

WHERE ( Charindex('9000413237',[Company].dbo.[customer].[Phone no])>0 ) 

будет просто использовать стандартное предположение для предиката неравенства, что будет возвращено 30% строк.

LIKEЗапрос (в вашем случае) , предположительно оценивает гораздо меньше строк будут соответствовать предикату.

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

Этот план вряд ли будет выбран с оценкой 30%. SQL Server посчитает, что дешевле сканировать весь кластерный индекс и избежать такого количества поисков. Смотрите эту статью на переломный момент для дополнительных примеров.


мне не понятно ваше объяснение. Вы говорите, что использовать лайк лучше, чем charindex?
ИТ-исследователь

3
@ITresearcher - Да, потенциально, вместо того, чтобы просто использовать общее предположение о том, сколько строк будет соответствовать условию ( 30%), он может посмотреть на предоставленный LIKEшаблон и статистику итоговых строк и получить более точную оценку. Вооружившись этим, он мог бы выбрать другой и более подходящий план.
Мартин Смит

3
... или, в "худшем случае", тот же план.
Аарон Бертран
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.