Как я могу оптимизировать/рефакторить предложение TSQL LIKE?

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

Мое предложение where выглядит следующим образом:

field1 LIKE '%' + @DESC + '%'
OR field2 LIKE '%' + @DESC + '%'
OR field3 LIKE '%' + @DESC + '%'

Кажется, это занимает около 24 секунд независимо от ввода...

Есть лучший способ сделать это? Гораздо предпочтительнее было бы меньше 10 (или 5!) секунд.

Спасибо за любую помощь.


person IronicMuffin    schedule 14.10.2009    source источник


Ответы (7)


Используйте полнотекстовый поиск и СОДЕРЖИТ. LIKE нельзя оптимизировать при поиске в середине поля, т.е. когда выражение LIKE начинается с «%», оно всегда будет выполнять полное сканирование таблицы.

person Remus Rusanu    schedule 14.10.2009
comment
вы можете использовать индекс, немного поработав, когда делаете LIKE '%'+string, см. ссылку в моем другом комментарии. - person KM.; 15.10.2009
comment
@KM: Интересный трюк, перевернутый столбец. Также хорошая аналогия с телефонной книгой, делает дело наглядно. - person Remus Rusanu; 15.10.2009
comment
хороший трюк, для obad нет ничего похожего на проблему '% text%'. - person HLGEM; 15.10.2009
comment
@KM: Это определенно должна быть форма «% test%», поэтому обратный метод отсутствует, хотя я видел это раньше, и это хитрый трюк. Мне придется попробовать полнотекстовый поиск, но, похоже, мне придется убедить администраторов баз данных правильно его индексировать. Спасибо за предложение. Я посмотрю, повысит ли производительность Full Text/Contains. Я помню, как делал это в старой базе данных с точно таким же запросом, и это было намного быстрее... не уверен, что новая делает по-другому. - person IronicMuffin; 15.10.2009
comment
После того, как администраторы баз данных выполнили полнотекстовый индекс таблиц, это сократило время поиска до 1-3 секунд. Спасибо за помощь! - person IronicMuffin; 21.10.2009
comment
как насчет поиска в начале строки? - person user384080; 04.11.2010
comment
Что делать, если переданный параметр равен нулю? - person Doug Chamberlain; 06.08.2013
comment
Это неверно, LIKE можно оптимизировать даже при поиске в середине поля. sqlservercentral.com/blogs/dwainsql/2014/03/26/ - person Mr. TA; 16.03.2018
comment
@Mr.TA, сужающий набор строк для уменьшения полного сканирования, не является оптимизацией индекса. Поскольку вы настаиваете на возрождении 9-летнего ответа, вы могли бы хотя бы взглянуть на современную альтернативу, такую ​​​​как columnstore... - person Remus Rusanu; 16.03.2018
comment
@RemusRusanu 1, я не говорил, что LIKE является единственным или предпочтительным решением. 2, вы читали страницу, на которую я дал ссылку? Он показывает, как использовать индекс, а не как сузить набор строк, что бы это ни значило. - person Mr. TA; 16.03.2018

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

person Stuart Ainsworth    schedule 14.10.2009
comment
@Stuart Ainsworth сказал Каждый раз, когда вы запускаете поиск LIKE с подстановочным знаком, вы выполняете сканирование, что не обязательно должно быть правдой, см. это: stackoverflow.com/questions/1388059/ - person KM.; 15.10.2009
comment
Теперь вы просто играете с семантикой; вы REVERSE столбца и индексируете его, а затем переворачиваете подобное предложение, чтобы оно не начиналось с подстановочного знака. Вы не начинаете поиск с подстановочного знака, поэтому не выполняете сканирование. Я признаю, что это интересное решение, и я должен иметь его в виду. - person Stuart Ainsworth; 15.10.2009
comment
Это неверно, LIKE можно оптимизировать даже при поиске в середине поля. sqlservercentral.com/blogs/dwainsql/2014/03/26/ - person Mr. TA; 16.03.2018
comment
Итак, почти 8 лет спустя я узнал кое-что новое :) Никогда не думал об удалении значений NULL из поиска строк с подстановочными знаками. - person Stuart Ainsworth; 17.03.2018

Вам действительно нужно начинать с подстановочного знака? Почему? Часто вы можете заставить пользователей вводить хотя бы первый символ. Я говорю об этом, потому что некоторые разработчики просто используют подстановочный знак как привычку, а не потому, что есть требование. В большинстве случаев пользователи смогут ввести первый символ, если только в поле не хранятся длинные строки (например, официальные названия аэропортов). В противном случае вам действительно нужно использовать полнотекстовое индексирование, хотя трюк KM с обратным довольно крут, если вам не нужен подстановочный знак в конце.

Если вы можете избежать убийств производительности, сделайте это.

person HLGEM    schedule 14.10.2009
comment
Да, мне нужен двусторонний подстановочный знак для этого запроса. Мне нужно найти что-то вроде «банана» в «Клубнично-банановом йогурте». - person IronicMuffin; 15.10.2009

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

Кален Делани в книге «Microsoft SQL Server 2008 Internals< /а>" говорит:

Сопоставление может иметь огромное значение, когда SQL Server должен просматривать почти все символы в строках. Например, посмотрите на следующее:

SELECT COUNT(*) FROM tbl WHERE longcol LIKE '%abc%'

Это может выполняться в 10 или более раз быстрее с двоичной сортировкой, чем с небинарной сортировкой Windows. А с данными varchar это выполняется в семь или восемь раз быстрее при сортировке SQL, чем при сортировке Windows.

person Martin Smith    schedule 19.09.2010
comment
Еще из книги Если у вас есть столбец типа varchar, вы можете ускорить процесс сортировки следующим образом: SELECT COUNT(*) FROM tbl WHERE longcol COLLATE SQL_Latin1_General_CP_CI_AS LIKE '%abc%'; - person yoel halb; 29.11.2012
comment
@yoelhalb ты, наверное, имел в виду _CP1_, а не _CP_ - person jazzcat; 21.02.2017

как насчет

field1 + field2 + field3 LIKE '%' + @DESC + '%'

or

CONTAINS(field1 + field2 + field3, @DESC)
person THEn    schedule 14.10.2009

Я попробовал одно из возможных решений. До этого решения даже запрос не возвращал результат и вызывал ошибку тайм-аута соединения.

В моем запросе был фильтр даты и другие критерии. Все остальные критерии были похожи на поиск. Одно ключевое слово столбца искало как «% abc%» в столбце ntext, и оно выполняло полное сканирование таблицы.

Решение:

Разделите запрос на 2 части. 1) Первая часть в CTE (Common Table Express) 2) Применить все критерии поиска в CTE.

WITH SearchData(Column1,Column2,Column3,Column4,........)
    AS
    (
    SELECT Column1,Column2,Column3,Column4,...........
    FROM myTable1 WITH(NOLOCK) 
            INNER JOIN MyTable2 WITH(NOLOCK) 
                ON MyTable1.id = MyTable2.Id
    WHERE (MyTable1.CreationTime >= '2014-04-27' AND MyTable1.CreationTime <= '2014-05-01') 
 )

    SELECT DISTINCT top 250 Column1,Column2,Column3,Column4
    FROM SearchData
    WHERE   (ISNULL(Column1,'') LIKE @Column1  +'%' OR @Column1 IS NULL)
            and (Column2 LIKE @Column2+ '%' OR @Column2 IS NULL)
            ...
            ...
            ...
            ...
            AND (Column10 like '%'+@Column10+'%' or @Column10 IS NULL)
            AND @Column1+@Column2+@Column3+........@Column10 <> ''  
            ORDER BY [CreationTime] DESC

Это сработало для меня.

person Agrawars    schedule 01.09.2015
comment
Я думаю, что использование предложения TOP с запросом, имеющим условие LIKE, всегда будет повышать производительность. Таким образом, предложение TOP, а не CTE, способствует повышению производительности, поскольку с TOP полное сканирование прерывается, как только просматривается необходимое количество записей. - person Sunil; 18.10.2015
comment
как примечание не по теме, использование WITH(NOLOCK) в каждом объединении очень опасно, вы должны быть очень осторожны с ним, иначе вы получите дублированные данные и т. д. Я вижу, что люди используют этот совет как стандартный способ оптимизации запросов, это не . вы всегда должны дважды подумать и проверить, как таблицы написаны (вставлены/обновлены) в вашем приложении, прежде чем вводить подсказку nolock. (просто говорю) - person Pedro Figueiredo; 18.12.2015

Если вы не можете использовать полнотекстовый поиск, вы можете увеличить скорость в 10 раз. Сделайте следующее:

1 Добавьте вычисляемое поле:

alter table TableName
add CalculatedColumnName as upper(Column1 + '|' + Column2...) collate Latin1_General_100_Bin2
persisted;

2 Добавьте индекс для вычисляемого поля:

create nonclustered index IDX_TableName_CalculatedColumnName
on TableName(CalculatedColumnName);

3 Измените текст запроса

select count(*)
from TableName
where CalculatedColumnName like '%' + upper(@ParameterValue) + '%' collate Latin1_General_100_Bin2

Источник: http://aboutsqlserver.com/2015/01/20/optimizing-substring-search-performance-in-sql-server

person Pavel Samoylenko    schedule 05.10.2017