Медленный SQL-запрос, включающий CONTAINS и OR - PullRequest
10 голосов
/ 30 июня 2011

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

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

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

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

Slow query

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

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

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

Fast query

Столбец, который мы используем СОДЕРЖИТ для поискаthrough - это столбец с изображением типа и состоит из xml-файлов размером от 1 до 20 000 *.

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

Есть ли что-нибудь очевидное, что мы здесь упускаем?

Заранее спасибо за ваше время!

Ответы [ 3 ]

4 голосов
/ 30 июня 2011

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

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

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

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

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

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

1 голос
/ 14 июня 2013

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

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

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

1 голос
/ 30 марта 2012

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

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

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

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

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

...