Как добавить больше запросов ИЛИ с помощью CONTAINS. Приводит запрос к сканированию?

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

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

Я был в состоянии решить производительность путем разделения два СОДЕРЖИТ поиск в свои собственные запросы 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

Ответ 1

Мне было бы интересно узнать, будет ли LEFT JOIN эквивалентным 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

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

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