Відповіді:
Відповідь, як завжди (добре, більшість часу), лежить у плані виконання.
Існують певні оператори, які вимагають, щоб усі рядки надходили до них, перш ніж вони могли почати обробляти ці рядки та передавати їх нижче, наприклад:
Їх або називають блокуючими, або зупиняють і переходять до операторів через це, і їх часто вибирають, коли оптимізатору здається, що для пошуку ваших даних доведеться обробити цілу купу даних.
Є й інші оператори, які можуть розпочати потокове передавання або передавати будь-які знайдені рядки разом
Коли запити починають повертати дані негайно, але не закінчуються негайно, зазвичай це знак того, що оптимізатор вибрав план, щоб швидко знайти та повернути деякі рядки, використовуючи операторів, що мають нижчу вартість запуску.
Це може статися через цілі рядків, введені або вами, або оптимізатором.
Це також може статися, якщо з якоїсь причини обраний поганий план (відсутність SARGability, нюхання параметрів, недостатня статистика тощо), але для розгляду потрібні ще більше копання.
Для отримання додаткової інформації ознайомтеся з блогом Роб Фарлі тут
І серія Пола Уайта про цілі ряду тут , тут , тут і тут .
Слід також зазначити, що, якщо ви говорите про SSMS, рядки з'являються лише після заповнення цілого буфера, а не лише мимоволі.
Якщо я розумію, що ви спостерігаєте, це те, як 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.
Ваше запитання не стосується SQLServer як такого, але:
Чи є спосіб це контролювати?
Коротка відповідь :
sqlcmd
замість ssms
або sqlcmd
-mode відssms
Довга відповідь :
Звичайно! Але не один - проб
sqlcmd
або sqlcmd
в -mode в ssms.spid
та отримайте повний список налаштувань сеансу. Порівняйте з налаштуваннями sqlcmd
сеансу. Якщо нічого не клацає - скопіюйте всі налаштування сесії з профілера у свій скрипт запиту, виконайте в sqlcmd
-mode та поступово перемикаючи налаштування, ви знайдете свого винуватця.Удачі!
Щоб додати відповідь sp_BlitzErik, візьміть приклад, використовуючи клавішу a NOT IN ()
з підбором . Для того, щоб визначити, чи є елемент в результаті вкладеного запиту, потрібно (як правило) отримати весь результат.
Отож, один із найпростіших способів покращити ефективність таких запитів - це переписати їх як те, LEFT OUTER JOIN
коли умова RIGHT
сторони є нульовою (ви, звичайно, можете перевернути її, але хто використовує RIGHT OUTER JOINS
?). Це дозволяє одразу почати повертати результати.
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 версія).
NOT EXISTS
але Oracle NOT IN
у запитах. Але сьогодні це має розглядатися як помилка в генераторі плану