Как заставить SQL Server обрабатывать предложения CONTAINS перед предложениями WHERE? - PullRequest
6 голосов
/ 22 июня 2011

У меня есть SQL-запрос, который использует как стандартные предложения WHERE, так и предложения полнотекстового индекса CONTAINS. Запрос строится динамически из кода и включает в себя переменное количество предложений WHERE и CONTAINS.

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

Однако SQL Server предпочитает обрабатывать предложения WHERE перед предложениями CONTAINS, что вызывает сканирование таблиц, и запрос выполняется очень медленно.

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

Есть ли способ заставить SQL Server обрабатывать КОНТЕЙНЫ прежде всего? Я не могу форсировать план (USE PLAN), потому что запрос строится динамически и сильно варьируется.

Примечание. У меня та же проблема на SQL Server 2005 и SQL Server 2008.

Ответы [ 3 ]

2 голосов
/ 22 июня 2011

Вы можете сообщить о своих намерениях оптимизатору, как это

SELECT
   *
FROM
    (
    SELECT *
    FROM


    WHERE
       CONTAINS
    ) T1
WHERE
   (normal conditions)

Однако SQL декларативен: вы говорите , что хотите, а не как делатьЭто.Таким образом, оптимизатор может решить игнорировать вложенность выше.

Вы можете заставить производную таблицу с помощью CONTAINS материализоваться до применения классического предложения WHERE.Я не гарантирую производительность.

SELECT
   *
FROM
    (
    SELECT TOP 2000000000
       *
    FROM
       ....
    WHERE
       CONTAINS
    ORDER BY
       SomeID
    ) T1
WHERE
   (normal conditions)
0 голосов
/ 22 июня 2011

Как я уже отмечал выше, это не такой чистый способ «материализации» производной таблицы, как предложение TOP, предложенное @gbn, но подсказка объединения циклов вынуждает порядок оценки и работала для меня в прошлом(по общему признанию обычно с двумя различными вовлеченными столами).Однако есть несколько проблем:

  • Запрос выглядит ужасно
  • Вы все еще не получаете никаких гарантий того, что другие параметры WHERE не будут оценены до тех пор, пока после объединенияМне будет интересно посмотреть, что вы получите)

Вот так, учитывая, что вы спросили:

SELECT OriginalTable.XXX
FROM (
    SELECT XXX
    FROM OriginalTable
    WHERE 
        CONTAINS XXX
) AS ContainsCheck
INNER LOOP JOIN OriginalTable 
    ON ContainsCheck.PrimaryKeyColumns = OriginalTable.PrimaryKeyColumns
        AND OriginalTable.OtherWhereConditions = OtherValues
0 голосов
/ 22 июня 2011

Попробуйте сделать это с 2 запросами без временных таблиц:

SELECT * 
FROM table
WHERE id IN (
    SELECT id 
    FROM table 
    WHERE contains_criterias
) 
AND further_where_classes
...