Запрос SQL Server медленный при разбиении на страницы

14

Я вижу странное поведение со следующим запросом T-SQL в SQL Server 2012:

SELECT Id 
FROM dbo.Person 
WHERE CONTAINS(Name, '"John" AND "Smith"')
ORDER BY Name

Только выполнение этого запроса дает мне около 1300 результатов менее чем за две секунды (включен полнотекстовый индекс Name)

Однако, когда я изменяю запрос на это:

SELECT Id 
FROM dbo.Person 
WHERE CONTAINS(Name, '"John" AND "Smith"')
ORDER BY Name
OFFSET 0 rows
FETCH NEXT 10 ROWS ONLY

Требуется больше 20 секунд, чтобы дать мне 10 результатов.

Следующий запрос еще хуже:

SELECT Id 
FROM ( 
    SELECT ROW_NUMBER() OVER (ORDER BY Name) AS RowNum, Id 
    FROM dbo.Person
    WHERE CONTAINS(Name, '"John" AND "Smith"') ) AS RowConstrainedResult 
WHERE RowNum >= 0 AND RowNum < 11 
ORDER BY RowNum

Это займет более 1,5 минут!

Есть идеи?

Медленный план

Медленный

Быстрый план

Быстро

VRS
источник
Что произойдет, если вы измените свой второй запрос на SELECT TOP 10 * .... ORDER BY Name?
Ламак
По каким столбцам производится индекс IX_PersonSearch ...? Вы получаете ключ поиска, потому что вы выбираете * из таблицы, а используемый индекс не содержит все выходные столбцы. Я думаю, что вы должны выбрать только те столбцы, которые вам нужны, а затем включить их в некластеризованный индекс как включенные столбцы, а не столбцы индекса.
Марсель Н.
Можете ли вы разместить свои индексы на столе (создать скрипт)?
3
Идентификатор всегда включен в каждый некластеризованный индекс. Так SQL Server может выполнять поиск ключей (по идентификатору).
USR
1
То, что я забыл упомянуть: Когда я делаю тот же запрос с LIKE вместо CONTAINS, это тоже быстро. (Нумерация страниц или нет)

Ответы:

7

Поскольку вы просто хотите TOP 10упорядочить по имени, он думает, что будет быстрее обработать индекс по nameпорядку и посмотреть, соответствует ли каждая строка CONTAINS(Name, '"John" AND "Smith"') )предикату.

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

Быстрый хак , чтобы остановить его , используя этот план будет изменить , ORDER BYчтобы ORDER BY Name + ''хотя использование CONTAINSTABLEв сочетании с FORCE ORDERтакже должны работать.

Мартин Смит
источник
3

Это похоже на классическую неправильную оценку избирательности. Не уверен, что с этим можно сделать, так как «драйвером» запроса является полнотекстовый поиск, который нельзя дополнить статистикой.

Попробуйте переписать where containsпредикат в inner join containstable( CONTAINSTABLE ) и применить подсказки порядка соединения, чтобы изменить форму плана.

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

USR
источник
Спасибо за ваш ответ, я попробовал. Результат тот же: если не использовать нумерацию страниц, запрос выполняется очень быстро. При разбиении на страницы это вдруг снова становится очень медленным: /
Хорошо, вы можете опубликовать план как изображение и ваш запрос? Я предполагаю, что нам еще не удалось создать желаемую форму.
USR
3

Мне удалось решить проблему:

Как я уже сказал в этом вопросе, для всех столбцов были индексы + статистика для каждого столбца. (Из-за устаревших запросов LIKE) Я удалил все индексы и статистику, добавил полнотекстовый поиск и вуаля, запрос стал действительно быстрым.

Кажется, показатели привели к другому Плану выполнения.

Спасибо всем большое за вашу помощь!

VRS
источник
1
Полное удаление индекса - это один из способов предотвратить его использование!
Мартин Смит