Подтвердить что ты не робот

Sql служит для полнотекстового поиска с Containstable очень медленно при использовании в JOIN!

Я использую полнотекстовый поиск sql 2008, и у меня возникают серьезные проблемы с производительностью в зависимости от того, как я использую Contains или ContainsTable.

Вот пример: (в таблице 1 содержится около 5000 записей, а в таблице1 есть закрытый индекс, который имеет все поля в предложении where. Я пытался упростить утверждения, поэтому простите меня, если есть проблемы с синтаксисом.)

Сценарий 1:

select * from table1 as t1
where t1.field1=90
and   t1.field2='something'
and   Exists(select top 1 * from containstable(table1,*, 'something') as t2 
where t2.[key]=t1.id)

результаты: 10 секунд (очень медленно)

Сценарий 2:

select * from table1 as t1
join containstable(table1,*, 'something') as t2 on t2.[key] = t1.id
where t1.field1=90
and   t1.field2='something'

результаты: 10 секунд (очень медленно)

Сценарий 3:

Declare @tbl Table(id uniqueidentifier primary key)
insert into @tbl select {key] from containstable(table1,*, 'something')

select * from table1 as t1
where t1.field1=90
and   t1.field2='something'
and  Exists(select id from @tbl as tbl where id=req1.id)

: доля секунды (супер быстрый)

В нижней строке, кажется, я использую Containstable в любом виде соединения или условия условия предложения оператора select, которое также имеет другие условия, производительность действительно плохая. Кроме того, если вы посмотрите на профилировщик, количество считываний из базы данных поступает на крышу. Но если я сначала сделаю полный текстовый поиск и поместил результаты в переменную таблицы, а с этой переменной все будет очень быстро. Количество чтений также значительно ниже. Кажется, что в "плохих" сценариях он каким-то образом застревает в цикле, что заставляет его читать много раз из базы данных, но, конечно, я не понимаю, почему.

Теперь вопрос в первую очередь, почему это происходит? а второй вопрос заключается в том, как масштабируемые переменные таблицы? что, если это приведет к 10 тысячам записей? все еще будет быстро.

Любые идеи? Благодаря

4b9b3361

Ответ 1

Я потратил довольно много времени на эту проблему и, основываясь на запуске многих сценариев, это то, что я выяснил:

если у вас есть Contains или ContainsTable в любом месте вашего запроса, это часть, которая выполняется сначала и, скорее, независимо. Это означает, что даже если остальные условия ограничивают ваш поиск только одной записью, ни Содержит, ни скрывает осторожность. Так что это похоже на параллельное выполнение.

Теперь, поскольку полнотекстовый поиск возвращает только поле Key, он сразу же ищет ключ как первое поле других индексов, выбранных для запроса. Итак, для примера выше, он ищет индекс с [ключ], поле1, поле2. Проблема в том, что он выбирает индекс для остальной части запроса на основе полей в предложении where. поэтому для вышеприведенного примера он выбирает охватываемый индекс, который у меня есть, что-то вроде field1, field2, Id. (Идентификатор таблицы совпадает с [Key], возвращаемым из полнотекстового поиска). Итак, резюме:

  • Выполняет сдерживаемый
  • выполняет оставшуюся часть запроса и выбирает индекс, основанный на том, где предложение запроса
  • Он пытается объединить эти два. Поэтому, если индекс, который он выбрал для остальной части запроса, начинается с поля [key], это нормально. Однако, если индекс не имеет поля [key] в качестве первого ключа, он начинает делать циклы. Он даже не выполняет сканирование таблицы, иначе прохождение 5000 записей не будет таким медленным. То, как он делает цикл, состоит в том, что он запускает цикл для общего количества результатов из FTS, умноженного на общее количество результатов от остальной части запроса. Поэтому, если FTS возвращает 2000 записей, а оставшаяся часть запроса возвращает 3000, она перебирает 2000 * 3000 = 6 000 000. Я не понимаю, почему.

Итак, в моем случае он выполняет полный текстовый поиск, а затем выполняет оставшийся запрос, но выбирает покрытый индекс, который у меня есть на основе поля1, field2, id (что неверно), и в результате он закручивает вверх. Если я изменю свой охваченный индекс на Id, field1, field2, все будет очень быстро.

Мое исключение заключалось в том, что FTS возвращает связку [key], остальная часть запроса возвращает связку [Id], а затем идентификатор должен быть сопоставлен с [ключ].

Конечно, я попытался упростить мой запрос здесь, но фактический запрос намного сложнее, и я не могу просто изменить индекс. У меня также есть сценарии, где текст, переданный в полном тексте, пуст, и в тех сценариях я даже не хочу присоединяться к сдерживаемым. В этих случаях изменение моего охваченного индекса, чтобы иметь поле id в качестве первого поля, приведет к катастрофе.

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

спасибо

Ответ 2

Обычно он работает очень быстро:

select t1.*, t2.Rank
    from containstable(table1, field2, 'something') as t2
        join table1 as t1 ON t1.id = t2.Key AND t1.field1=90
    order by t2.Rank desc

Существует большая разница, когда вы ставите критерии поиска: в JOIN или WHERE.

Ответ 3

Я собираюсь предположить, что ваша проблема такая же, как и в другом потоке, с которым я связан. Вы находите, что проблема возникает с несколькими терминами поиска слов?

Если так, то мой ответ из этого потока будет применяться.

От http://technet.microsoft.com/en-us/library/cc721269.aspx#_Toc202506240

Самое главное, что правильный тип соединения выбран для полнотекстовый запрос. мощность оценка по FulltextMatch STVF очень важно для правильного плана. Итак, первое, что нужно проверить, это Полнотекстовая оценка мощности. Это примерное количество просмотров в индексе полнотекстового поиска строка. Например, в запросе в Рисунок 3 должен быть близок к количество документов, содержащих долгосрочного "слова. В большинстве случаев это должно быть очень точным, но если оценка было далеко, вы могли создавать плохие планы. Оценка для единичные термины, как правило, очень хорошие, но оценка нескольких терминов, таких как фразы или запросы ИИ более сложны так как невозможно узнать, что пересечение членов в индексе будет основываться на частоте термины в индексе. Если мощность оценка хорошая, плохой план вероятно, вызвано запросом оптимизационная модель затрат. Единственный способ Исправить проблему плана - использовать запрос намек на принудительное присоединение или ОПТИМИЗАЦИЯ ДЛЯ.

Таким образом, он просто не может знать, из информации, которую он хранит, могут ли быть близкими друг к другу два поисковых термина, которые могут быть вполне независимыми или обычно встречаться вместе. Возможно, у вас должно быть 2 отдельных процедуры для однословных запросов, которые вы позволяете оптимизатору делать свои вещи, и один для многословных поисковых терминов, на которые вы принудительно устанавливаете "достаточно хороший" план (sys.dm_fts_index_keywords может помочь, если вы хотите сделать приблизительная оценка мощности).

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

В полнотекстовом поиске SQL Server 2008 у нас есть возможность изменить план, который   созданный на основе оценки мощности используемого поискового термина. Если план запроса фиксирован (как в параметризованном запросе внутри хранимой процедуры), этот шаг делает  не состоится. Поэтому скомпилированный план всегда выполняет этот запрос, даже если этот план не идеален для данного поискового термина.

Поэтому вам может понадобиться использовать функцию RECOMPILE.