2015-01-24 5 views
0

Когда я объединяю два условия в предложении WHERE моего запроса, для выполнения требуется более минуты. Если я разделился на два разных запроса, они оба работают примерно через 1 секунду.SQL - ИЛИ заставляет запрос работать очень медленно

Любые мысли? Смотрите ниже:

Это занимает более чем минута

SELECT 
    COUNT(b.BookKey) 
from 
    Books b (nolock) 
    inner join BookPublishCities bp (nolock) 
     on b.BookKey = bp.BookKey 
where 
    contains(bp.PublishRegionName, @SearchTerm) OR contains(b.BookTitle, @SearchTerm) 

Вместе они составляют около 1 вторых

SELECT 
    COUNT(b.BookKey) 
from 
    Books b (nolock) 
    inner join BookPublishCities bp (nolock) 
     on b.BookKey = bp.BookKey 
where 
    contains(bp.PublishRegionName, @SearchTerm) 

-- and... 

SELECT 
    COUNT(b.BookKey) 
from 
    Books b (nolock) 
    inner join BookPublishCities bp (nolock) 
     on b.BookKey = bp.BookKey 
where 
    contains(b.BookTitle, @SearchTerm) 
  • Существует полнотекстовый индекс Books.BookTitle и BookPublishCities.PublishRegionName ,
  • Обе таблицы содержат около 500 тыс. Строк. Причина, по которой я не включил PublishRegionName в таблицу Books, состоит в том, что вам разрешен только один полнотекстовый индекс для каждой таблицы.
  • Существует индекс на BookPublishCities.BookKey

Я просто не знаю, почему отдельные запросы намного быстрее. Мысли?

+1

Возможный дубликат [Полнотекстового поиска SQL Server значительно снижается при использовании «ИЛИ» в разделе where] (http://stackoverflow.com/questions/4100589/sql- server-full-text-search-performance-dramally-down-when-using-or-in-whe) –

+0

Спасибо @rtumaykin. Можете ли вы дать подробную информацию о 2-м ответе в этой должности? «Реальная проблема заключается в том, что с помощью« ИЛИ »на месте нельзя выбрать правильный индекс, поскольку« правильный »индекс будет зависеть от результата первой оценки для каждой отдельной строки. Поэтому СУБД выбирает один индекс (скорее всего, правильная для первой части «OR»), и в случае, если первая оценка возвращается как «ложная», запускает вторую, неиндексированную, что замедляет работу. Производительность для этого во многом зависит от того, насколько часто первые оценки возвращает «false». – Ricky

+1

Не видя планов исполнения, на самом деле не так много догадываться. Оптимизатор пытается выбрать баланс между оптимальным планом выполнения и не тратить слишком много времени на его создание. Я могу думать о 3 возможных проблемах: 1. Оптимизатор отказывается от OR и прибегает к полному сканированию таблицы. 2. Оптимизатор имеет план выполнения кэширования, который был создан на основе @SearchTerm, который был законно быстрее выполнить с использованием полного scan, и теперь он просто повторно использует его 3. Оптимизированное решение о том, что стоимость OR превышает порог параллелизма и пытается выполнить запрос с использованием нескольких параллельных потоков. –

ответ

1

or может представлять проблему для оптимизаторов SQL. Обычно эта проблема возникает с условиями join, но это также может происходить здесь. Попробуйте использовать union и посмотреть, если это быстрее:

SELECT COUNT(*) 
FROM ((SELECT bookkey 
     FROM BookPublishCities bp (nolock) 
     WHERE contains(bp.PublishRegionName, @SearchTerm) 
    ) UNION ALL 
     (SELECT BookKey 
     FROM Books b (nolock) 
     WHERE contains(b.BookTitle, @SearchTerm) 
    ) 
    ) b; 

Обратите внимание, что я упростил подзапросов. join s не кажутся необходимыми с учетом логики - хотя в некоторых случаях они могут быть важными (например, если соединения используются для фильтрации, поскольку ключи книги не находятся в обеих таблицах).

Это также может не возвращать точно такие же результаты, потому что предположительно название и регион могут совпадать. Это также может генерировать дубликаты в вашем запросе, поэтому вам может понадобиться count(distinct) во внешнем запросе.

+0

спасибо. FYI причина, по которой я включил внутренние объединения в отдельные запросы, состояла в том, чтобы проиллюстрировать тот факт, что все, что мне нужно было сделать, это удалить условия OR, чтобы значительно увеличить скорость. – Ricky

+0

Я немного новичок в SQL. Что касается лучших практик и удобочитаемости, я бы подумал, что это был бы предпочтительный выбор. Я просто не могу заставить его работать так же быстро, как запросы UNION. Это обычное явление? – Ricky

+0

@ Ricky. , , Иногда это происходит. SQL - довольно полезный язык, и оптимизаторы вполне разумны, но они не поймают все. –

-2

Set SHOWPLAN_ALL on. Осмотрите план комбинации и сравните ее с физическими лицами. Возможно, вам понадобится дать некоторые подсказки для QEP

+0

Подсказки запроса (в том числе и особенно 'NOLOCK') должны использоваться только как абсолютное последнее средство и только если вы точно знаете, что делаете. – alroc

+0

Неужели nolock заставляет запрос замедляться? – Ricky

Смежные вопросы