Як (і чому) ТОП впливає на план виконання?


35

Для помірно складного запиту, який я намагаюся оптимізувати, я помітив, що видалення TOP nпункту змінює план виконання. Я б здогадався, що коли запит включає TOP nв себе двигун бази даних, він би запустив запит, ігноруючи TOPзастереження, а потім наприкінці просто зменшить цей результат, встановлений на n кількість рядків, які запитували. Графічний план виконання, схоже, вказує, що це так - TOPце "останній" крок. Але, здається, там відбувається більше.

Моє запитання полягає в тому, як (і навіщо) пункт TOP n впливає на план виконання запиту?

Ось спрощена версія того, що відбувається в моєму випадку:

Запит відповідає рядкам із двох таблиць, A і B.

Без TOPпункту, оптимізатор розраховує, що з таблиці А буде розміщено 19 к рядків та 46 к рядків таблиці B. Фактична кількість рядків, що повертаються, становить 16 к для А та 13 к для Б. Хеш-матч використовується для приєднання цих двох наборів результатів для всього 69 рядків (тоді застосовується сортування). Цей запит відбувається дуже швидко.

Коли я додаю, TOP 1001оптимізатор не використовує хеш-відповідність; натомість він спочатку сортує результати з таблиці A (така ж оцінка / фактична 19k / 16k) та робить вкладений цикл проти таблиці B. Орієнтовна кількість рядків для таблиці B зараз 1, і дивно, що TOP nбезпосередньо впливає на Орієнтовна кількість страт (пошук індексу) проти B - вона, як видається, завжди дорівнює 2n + 1 , або в моєму випадку 2003. Ця оцінка відповідно змінюється, якщо я змінюсь TOP n. Звичайно, оскільки це вкладене об'єднання, фактична кількість виконань становить 16 к (кількість рядків з таблиці А), і це уповільнює запит.

Справжній сценарій є трохи складнішим, але це фіксує основну ідею / поведінку. В обох таблицях здійснюється пошук за допомогою індексів. Це видання SQL Server 2008 R2 Enterprise.


У запиті є ORDER BYпункт. Додавання TOPзмін там, де в плані відбувається такий сорт, але мене більше хвилює те, як це впливає на кількість виконання покажчиків індексу проти таблиці B ... (звичайно, вони можуть бути пов'язані - я не знаю)
Девід

1
Пов’язана дискусія: FAST num_rowsпідказка щодо запиту.
Рем Русану

Відповіді:


39

Я б здогадався, що коли запит включає TOP n, двигун бази даних буде запускати запит, ігноруючи пункт TOP, а потім наприкінці просто зменшити цей результат, встановлений на n кількість рядків, які вимагали. Графічний план виконання, схоже, вказує, що це так - TOP є "останнім" кроком. Але, здається, там відбувається більше.

Способи викладеного вище змушують мене думати, що у вас може бути неправильна думка про те, як виконується запит. Оператор у плані запитів не є кроком (де повний набір результатів попереднього кроку оцінюється наступним.

SQL Server використовує конвеєрну модель виконання, де кожен оператор відкриває такі методи, як Init () , GetRow () та Close () . Як підказує ім'я GetRow () , оператор виробляє по одному рядку за потребою (як того вимагає його батьківський оператор). Це задокументовано у посиланні « Логічні та фізичні оператори Книги» , більш докладно в моєму дописі « Чому Плани запитів працюють назад . Ця модель строків одночасно є важливою для формування здорової інтуїції для виконання запитів.

Моє запитання полягає в тому, як (і чому) впливає TOPn-пункт на план виконання запиту?

Деякі логічні операції, такі як TOPнапівпоєднання та FAST n натяк на запит, впливають на те, як оптимізатор запитів коштує альтернативи плану виконання. Основна ідея полягає в тому, що одна можлива форма плану може повернути перші n рядків швидше, ніж інший план, оптимізований для повернення всіх рядків.

Наприклад, об'єднання вкладених циклів з індексом часто є найшвидшим способом повернути невелику кількість рядків, хоча хеш або об'єднання об'єднань зі скануванням може бути більш ефективним для великих наборів. Те, як оптимізатор запитів пояснює ці варіанти, встановлюючи ціль рядка в конкретній точці логічного дерева операцій.

Мета рядка змінює спосіб оплати альтернатив плану запитів. Суть його полягає в тому, що оптимізатор починається з витрат кожного оператора так, як ніби потрібен повний набір результатів, встановлює ціль рядка у відповідній точці, а потім працює назад вниз по дереву плану, оцінюючи кількість рядків, які, на його думку, потрібно буде вивчити. для досягнення мети рядка

Наприклад, логічний TOP(10)встановлює ціль рядка 10 у конкретній точці дерева логічних запитів. Витрати операторів, які ведуть до цілі рядка, змінюються, щоб оцінити, скільки рядків потрібно створити для досягнення мети рядка. Цей розрахунок може стати складним, тому простіше зрозуміти все це за допомогою повністю відпрацьованого прикладу та анотованих планів виконання. Цілі рядків можуть впливати більше, ніж вибір типу приєднання або те, чи шукають і шукають перевагу для сканування. Детальніше про це тут .

Як завжди, план виконання, обраний на основі цілі рядка, підпорядковується можливостям оптимізатора та міркуванню якості наданої йому інформації. Не кожен план із ціллю рядків на практиці швидше створить необхідну кількість рядків, але відповідно до моделі калькуляції це буде.

Якщо план цілей рядка виявляється не швидшим, зазвичай існують способи змінити запит або надати оптимізатору кращу інформацію таким чином, що найкраще вибраний природний план. Який варіант підходить у вашому випадку, залежить від деталей курсу. Функція цілі рядка, як правило, дуже ефективна (хоча є помилка, на яку слід спостерігати, коли вона використовується в паралельних планах виконання).

Ваш конкретний запит та план можуть не підходити для детального аналізу тут (будь-якими способами надайте фактичний план виконання, якщо хочете), але, сподіваємось, викладені тут ідеї дозволять вам досягти прогресу вперед.


12

Коли ви використовуєте TOP, оптимізатор бачить можливість зробити менше роботи. Якщо ви попросите 10 рядків, то є хороший шанс, що не потрібно споживати весь набір. Тож оператор TOP може бути просунутий набагато далі праворуч. Він буде запитувати рядки від наступного оператора (праворуч), поки не отримає достатньо.

Ви вказуєте, що без TOP запит сортує дані в самому кінці. Якщо двигун міг би знати, скільки рядків буде задоволено приєднанням заздалегідь, він цілком може вибрати аналогічний план, розташувавши TOP зліва. Але якщо зусилля зробити хеш-матч відносно високими, і, мабуть, немає варіанту для об'єднання об'єднань, оптимізатор, можливо, віддасть перевагу фільтруванню ТОП далі праворуч.

Коли запитується таблиця B, вона отримує окремий рядок за один раз. Ось чому оцінка дорівнює 1. Це також передбачає, що він знайде лише цей рядок у 50% часу. Тож він здогадується, що для її знаходження потрібно 2n + 1.


Це не здається правильним, що орієнтовна кількість рядків буде змінюватися залежно від способу отримання даних. Те, як вони отримують дані, не повинно впливати на кардинальність. Зміна способу її отримання замість цього відображатиметься на кількості страт, правда?
Девід,

"Орієнтовна кількість рядків" - на виконання. У вкладеному циклі цілком ймовірно, що він буде виконуватися не один раз.
Роб Фарлі

Це буде інша поведінка, ніж фактична кількість рядків та (фактична) кількість страт тоді. Якщо фактичний план показує 16,834 фактичних виконання та 15 407 повернених фактичних рядків, я вважаю, що це прагнуло 16 к, але було знайдено лише 15 к, що відповідає присудку. Якби це означало 15k рядків за виконання, це було б 15k * 16k = 240 мільйонів рядків - приблизно в 10 разів більше, ніж таблиця ...
David

Також я не впевнений, що я дотримуюся останнього твердження вашої відповіді. Коли ви говорите, що 2n + 1 прагне знайти "це", що ви розумієте під "воно"? Невже не один ряд? Ви маєте на увазі, що оптимізатор припускає, що для будь-якого даного рядка в А є 50% шансу, що він буде збігатися з B, і тому йому потрібно буде "спробувати" 2003 рядки з A, щоб отримати 1001 збігу з B? Чи подібна документація Microsoft де-небудь задокументована? І що це стосується TOPпункту? Дякуємо за вашу відповідь / терпіння.
Девід

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