Чому SQL Server повертає деякі рядки під час виконання запиту, а іноді ні?


33

Є запити, коли ми натискаємо "Execute", він показує деякі рядки, і він постійно зростає, але запит ще не закінчений. Але іноді він чекає до кінця запиту.

Чому це відбувається? Чи є спосіб це контролювати?

Відповіді:


43

Відповідь, як завжди (добре, більшість часу), лежить у плані виконання.

Існують певні оператори, які вимагають, щоб усі рядки надходили до них, перш ніж вони могли почати обробляти ці рядки та передавати їх нижче, наприклад:

  • Hash Join (на створенні хеш-таблиці)
  • Хеш-матч
  • Сортувати (за винятком різного хеш-потоку)

Їх або називають блокуючими, або зупиняють і переходять до операторів через це, і їх часто вибирають, коли оптимізатору здається, що для пошуку ваших даних доведеться обробити цілу купу даних.

Є й інші оператори, які можуть розпочати потокове передавання або передавати будь-які знайдені рядки разом

  • Вкладені петлі
  • Індекс підтримує об'єднання об'єднань
  • Потокові агрегати

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

Це може статися через цілі рядків, введені або вами, або оптимізатором.

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

Для отримання додаткової інформації ознайомтеся з блогом Роб Фарлі тут

І серія Пола Уайта про цілі ряду тут , тут , тут і тут .

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


14

Якщо я розумію, що ви спостерігаєте, це те, як Management Studio надає рядки, і мало стосується того, як SQL Server повертає рядки. Насправді часто, коли ви повертаєте великі результати до SSMS та намагаєтесь вивести їх у сітку, SSMS не може йти в ногу, і SQL Server закінчує очікування, коли програма обробить більше рядків. У цьому випадку ви побачите, що SQL Server накопичує ASYNC_NETWORK_IOочікування.

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

Коли у вас є кілька операторів, і ви хочете змусити буфер виводити результати виводу на панель повідомлень, ви можете використовувати невеликий трюк друку між операторами:

RAISERROR('', 0, 1) WITH NOWAIT;

Але це не допоможе, коли ви намагаєтеся змусити SSMS швидше відображати рядки, коли весь вихід надходить з одного оператора.

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

Є такі хаки OPTION (FAST 100), які оптимізують для отримання цих перших 100 рядків (або будь-яких 100 рядків, якщо немає зовнішньої ORDER BY), але це може призвести до набагато повільнішого пошуку для решти рядків і плану, який більше загалом неефективна, тому насправді не можливий варіант IMHO.


1

Ваше запитання не стосується SQLServer як такого, але:

  • SQLServer
  • мережа
  • SSMS як клієнтська програма

Чи є спосіб це контролювати?

Коротка відповідь :

  1. Спробуйте sqlcmdзамість ssmsабо sqlcmd-mode відssms
  2. Перевірте налаштування підключення та сеансу

Довга відповідь :

Звичайно! Але не один - проб

  1. Виконайте свій запит за допомогою sqlcmdабо sqlcmdв -mode в ssms.
  2. Якщо ви хочете виключити роль мережі - запустіть свій запит на сервері за допомогою з'єднання загальної пам'яті.
  3. Якщо продуктивність запитів незадовільна навіть при підключенні до спільної пам'яті - проаналізуйте свої плани виконання. Якщо запит працює погано через мережу, зателефонуйте до адміністратора мережі. Якщо ваш запит працює лише в SSMS - читайте далі.
  4. Тепер ми впевнені, що проблеми є на стороні клієнта (в цьому випадку є sms). Подивіться на параметри з'єднання та сеансу в SSMS. Не вірте інтерфейсу ssms та зверніться до SQL Profiler: знайдіть своє з'єднання spidта отримайте повний список налаштувань сеансу. Порівняйте з налаштуваннями sqlcmdсеансу. Якщо нічого не клацає - скопіюйте всі налаштування сесії з профілера у свій скрипт запиту, виконайте в sqlcmd-mode та поступово перемикаючи налаштування, ви знайдете свого винуватця.

Удачі!


-2

Щоб додати відповідь sp_BlitzErik, візьміть приклад, використовуючи клавішу a NOT IN ()з підбором . Для того, щоб визначити, чи є елемент в результаті вкладеного запиту, потрібно (як правило) отримати весь результат.

Отож, один із найпростіших способів покращити ефективність таких запитів - це переписати їх як те, LEFT OUTER JOINколи умова RIGHTсторони є нульовою (ви, звичайно, можете перевернути її, але хто використовує RIGHT OUTER JOINS?). Це дозволяє одразу почати повертати результати.


Я не думаю, що так. Якщо порівнювані стовпці не є нульовими, то результати мають бути однаковими, а плани - зазвичай - однаковими для 3-х версій антиз'єднання (НЕ В, НЕ ІСНУЄТЬСЯ, ЛІВНЕ ПРИЄДНАЙТЕСЬ / НУЛЬНО). Не варто отримувати весь результат.
ypercubeᵀᴹ

Якщо підселекція є дійсно складною, що для запиту, що виробляється, необхідно оцінити весь підвідбір перед тим, як перевірити стан NOT IN WHERE t.x IN (<complex SELECT subquery>), еквівалентний ЛІВНІЙ ПРИЄДНАЙТЕСЬ LEFT JOIN (<complex SELECT subquery>) AS r ON r.x = t.x .... WHERE r.x IS NULL, то підзапит також буде оцінений (такий самий складний план із NOT IN версія).
ypercubeᵀᴹ

@ ypercubeᵀᴹ Це працювало для мене в минулому. Я бачив, що запити тривають від декількох хвилин до повернення до другої секунди.
JimmyJames

@ ypercubeᵀᴹ Я зібрав простий приклад в Oracle (вибачте, я не маю доступу до SQLServer на даний момент), і вони, безумовно, мали різні плани пояснення. Можливо, вони не мали суттєвих відмінностей, але вони виглядають досить різними.
JimmyJames

@JimmyJames: це не простий спосіб, якщо ви хочете стабільної продуктивності, і такі "оптимізації" дуже чутливі до версії SQLServer. І не помиляйтесь, звертаючись до Oracle (яка версія?). Історично кращий SQLServer, NOT EXISTSале Oracle NOT INу запитах. Але сьогодні це має розглядатися як помилка в генераторі плану
Алекс Ю.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.