Запит на 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 хвилин!

Будь-які ідеї?

Повільний план

Повільно

Швидкий план

Швидкий


Що станеться, якщо змінити другий запит на SELECT TOP 10 * .... ORDER BY Name?
Ламак

На яких стовпцях робиться індекс IX_PersonSearch ...? Ви отримуєте пошук ключа, оскільки ви вибираєте * з таблиці, а використаний індекс не містить усіх вихідних стовпців. Я думаю, ви повинні вибрати лише потрібні стовпці, а потім включити їх у некластеризований індекс як стовпці, що включаються, а не стовпці з індексами.
Марсель Н.

Чи можете ви розмістити індекси на таблиці (створити сценарій)?

3
Ідентифікатор завжди включений у кожен некластеризований індекс. Це спосіб, яким SQL Server здатний проводити пошук (за ідентифікатором).
usr

1
Що я забув зазначити: Коли я роблю той самий запит з LIKE замість ЗМІСТ, теж швидко. (Заборонено чи ні)

Відповіді:


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

3

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

Як я вже говорив у запитанні, в усіх стовпцях були пробіли + статистика для кожного стовпця. (Через застарілі запити LIKE) Я видалив усі проміжки та статистику, додав повний текст пошуку та voilà, запит став дійсно швидким.

Здається, індиси призвели до іншого плану виконання.

Дуже дякую всім за допомогу!


1
Добре видалення індексу - це один із способів запобігти його використанню.
Мартін Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.