Медленный SQL-запрос с участием CONTAINS и OR

У нас была проблема, мы надеялись, что хорошие люди Qaru могут нам помочь. Были запущены SQL Server 2008 R2 и возникают проблемы с запросом, который занимает очень много времени для работы на умеренном наборе данных, около 100000 строк. Мы используем CONTAINS для поиска через xml файлы и LIKE в другом столбце для поддержки ведущих wild-карточек.

Мы воспроизвели проблему со следующим небольшим запросом, который занимает около 35 секунд:

SELECT something FROM table1 
WHERE (CONTAINS(TextColumn, '"WhatEver"') OR  
        DescriptionColumn LIKE '%WhatEver%')

План запроса:

Slow query

Если мы изменим запрос выше на использование UNION, время работы сократится с 35 секунд до < 1 секунда. Мы хотели бы избежать использования этого подхода для решения проблемы.

SELECT something FROM table1 WHERE (CONTAINS(TextColumn, '"WhatEver"') 
UNION
(SELECT something FROM table1 WHERE (DescriptionColumn LIKE '%WhatEver%'))

План запроса:

Fast query

Столбец, использующий CONTAINS для поиска, представляет собой столбец с типом изображения и состоит из xml файлов размером от 1 до 20 тысяч.

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

Есть ли что-то откровенно очевидное здесь?

Заранее благодарим за ваше время!

Ответ 1

Почему вы используете DescriptionColumn LIKE '%WhatEver%' вместо CONTAINS(DescriptionColumn, '"WhatEver"')?

CONTAINS, очевидно, является полнотекстовым предикатом и будет использовать механизм полнотекстового SQL Server для фильтрации результатов поиска, однако LIKE является "обычным" ключевым словом SQL Server, поэтому SQL Server не будет использовать Full -Text для запроса этого запроса. В этом случае, поскольку термин LIKE начинается с подстановочного знака, SQL Server не сможет использовать какие-либо индексы, чтобы помочь с запросом, который, скорее всего, приведет к сканированию таблицы и/или к более бедным чем при использовании полнотекстового движка.

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

  • Вариант запроса UNION выполняет сканирование таблицы с помощью table1 - сканирование таблицы выполняется не быстро, однако из-за того, что в таблице относительно мало строк, это не выполняется медленно (по сравнению с контрольный показатель 35s).

  • В ответе OR запроса SQL Server сначала использует полнотекстовый движок для фильтрации на основе CONTAINS, а затем продолжает выполнять поиск RDI в каждой соответствующей строке в результате, чтобы фильтр, основанный на предикате LIKE, однако по какой-то причине SQL Server значительно недооценил количество строк (это может случиться с некоторыми типами предикатов), и поэтому продолжает выполнять несколько тысяч запросов RDI, которые заканчиваются невероятно медленными ( сканирование таблицы было бы намного быстрее).

Чтобы понять, что происходит, вам нужно получить план запроса.

Ответ 2

Вы, ребята, попробовали это:

SELECT *
FROM table
WHERE CONTAINS((column1, column2, column3), '"*keyword*"')  

Вместо этого:

SELECT *
FROM table
WHERE CONTAINS(column1, '"*keyword*"') 
OR CONTAINS(column2, '"*keyword*"') 
OR CONTAINS(column3y, '"*keyword*"') 

Первый из них намного быстрее.

Ответ 3

Я просто столкнулся с этим. Сообщается, что это ошибка на SQL Server 2008 R2:

http://www.arcomit.co.uk/support/kb.aspx?kbid=000060

Ваш подход к использованию UNION из двух выборок вместо OR является обходным решением, которое они рекомендуют в этой статье.