Как добавить больше запросов ИЛИ с помощью CONTAINS. Приводит запрос к сканированию? - PullRequest
10 голосов
/ 25 мая 2010

У меня есть простой запрос, основанный на двух полнотекстовых индексированных таблицах, но он работает очень медленно, когда у меня есть CONTAINS в сочетании с любым дополнительным поиском ИЛИ . Как видно из плана выполнения, два полнотекстовых поиска снижают производительность. Если я запрашиваю только 1 из КОНТЕЙНОВ или ни того, ни другого, запрос будет менее секунды, но в момент добавления ИЛИ в смесь запрос становится неудачным.

Эти две таблицы не являются чем-то особенным, они не слишком широки (42 столбца в одной, 21 в другой; возможно, 10 столбцов имеют индексирование FT в каждой) или даже содержат очень много записей (36 тысяч записей в самой большой из два).

Мне удалось решить проблему производительности, разделив два CONTAINS поиска на их собственные SELECT запросы и затем UNION на три. Является ли этот обходной путь UNION моей единственной надеждой?

SELECT     a.CollectionID
FROM       collections    a
INNER JOIN determinations b ON a.CollectionID = b.CollectionID 
WHERE      a.CollrTeam_Text LIKE '%fa%'
           OR CONTAINS(a.*, '"*fa*"')
           OR CONTAINS(b.*, '"*fa*"')

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

execution plan

Ответы [ 4 ]

6 голосов
/ 25 мая 2010

Мне было бы любопытно посмотреть, будет ли ЛЕВОЕ СОЕДИНЕНИЕ с эквивалентным CONTAINSTABLE работать лучше. Что-то вроде:

SELECT     a.CollectionID
FROM       collections    a
INNER JOIN determinations b ON a.CollectionID = b.CollectionID 
LEFT JOIN CONTAINSTABLE(a, *, '"*fa*"') ct1 on a.CollectionID = ct1.[Key]
LEFT JOIN CONTAINSTABLE(b, *, '"*fa*"') ct2 on b.CollectionID = ct2.[Key]
WHERE      a.CollrTeam_Text LIKE '%fa%'
           OR ct1.[Key] IS NOT NULL
           OR ct2.[Key] IS NOT NULL
3 голосов
/ 25 мая 2010

Я собирался предложить UNION каждому в качестве своего собственного запроса, но, читая ваш вопрос, я увидел, что вы нашли это.Я не могу придумать лучшего способа, так что если это поможет.Метод UNION является распространенным подходом к плохо выполняющемуся запросу, в котором есть несколько условий ИЛИ, каждый из которых работает хорошо сам по себе.

1 голос
/ 25 мая 2010

Я бы, наверное, использовал СОЮЗ. Если вы действительно против, вы можете попробовать что-то вроде:

SELECT a.CollectionID
FROM collections a
  LEFT OUTER JOIN (SELECT CollectionID FROM collections WHERE CONTAINS(*, '"*fa*"')) c
    ON c.CollectionID = a.CollectionID
  LEFT OUTER JOIN (SELECT CollectionID FROM determinations WHERE CONTAINS(*, '"*fa*"')) d
    ON d.CollectionID = a.CollectionID
WHERE a.CollrTeam_Text LIKE '%fa%'
   OR c.CollectionID IS NOT NULL
   OR d.CollectionID IS NOT NULL
0 голосов
/ 26 мая 2010

У нас возникла точно такая же проблема, и в то время мы объясняли это тем, что наш запрос был плохо сформирован - SQL 2005 позволил нам сойти с рук, а 2008 - нет.

В итоге мы разбили запрос на 2 SELECT, которые были вызваны с использованием IF. Рад, что у кого-то была такая же проблема, и это известная проблема. Мы видели запросы к таблице с ~ 150 000 строк + полнотекстовый переход от <1 секунды (2005 г.) до 30+ секунд (2008 г.). </p>

...