CPU
Каждый запрос, поступающий на сервер (т. Е. Каждый «пакет»), будет связан с «заданием», см. sys.dm_os_tasks . Задача ставится в очередь в «планировщике», который грубо говоря говорит о ядре процессора, см. sys.dm_os_schedulers . У каждого планировщика есть несколько «рабочих» (т. Е. Потоков или волокон, см. sys.dm_os_workers ), и свободный работник выберет следующую задачу из очереди планировщика и «убежит» с ней, выполняя ее до тех пор, пока задание завершено (т.е. запросы выполнены). Этот механизм планирования применяется к всему внутри SQL, включая системные задачи, исполняемый код CLR и т. Д. И т. Д.
Количество задач, которые можно создать, ограничено доступной памятью. Запросы («пакеты») не равняются задачам «один-к-одному», так как некоторые запущенные запросы планируют выполнение большего количества задач, типичным примером являются параллельные запросы. Число рабочих в системе является динамическим, но ограничено параметром конфигурации «max worker threads
». Если рабочий предел был достигнут, то новые запланированные задачи будут поставлены в очередь в планировщиках, но не будут подняты, пока рабочий не освободится (завершит задачу) и не станет доступным. Когда это условие достигается, оно называется «нехватка рабочих ресурсов» и приводит к не отвечающему серверу, поскольку новые рукопожатия при входе клиента требуют выполнения задач входа в систему (сервер, по-видимому, отклоняет соединения), а новые запросы существующего клиента будут поставлены в очередь позади задач ожидания. (серверу требуется много времени для ответа на тривиальные запросы).
Так что, если у вас большое количество параллельных, долго выполняющихся запросов, вы будете использовать большое количество работников, выполняющих много, долго выполняющихся задач. Это уменьшает размер пула свободных рабочих, в результате чего меньше рабочих, доступных для обслуживания других, коротких задач, поступающих на сервер (таких как OLTP-запросы, рукопожатия при входе в систему и т. Д.). Сервер не отвечает, поскольку задачи накапливаются в очередях планировщиков (это можно увидеть в столбце sys.dm_os_schedulers
DMV work_queue_count
). В крайних случаях вы можете эффективно истощить систему работников, в результате чего сервер будет полностью не реагировать, пока некоторые из работников не освободятся.
Память
План запроса, содержащий параллельные операции, обычно связан с полным сканированием больших индексов (больших таблиц). Сканирование индекса выполняется путем обхода его конечных страниц, а чтение всех конечных страниц в большой таблице означает, что все эти страницы должны присутствовать в памяти в тот или иной момент во время выполнения запроса. Это, в свою очередь, создает спрос на свободные страницы из пула буферов для размещения отсканированных страниц. Потребность в свободных страницах создает нагрузку на память, что приводит к тому, что кэши получают уведомление о начале удаления старых записей, а старые страницы данных в пуле буферов удаляются. Уведомления о кеше можно увидеть в sys.dm_os_memory_cache_clock_hands . Удаление страниц данных можно контролировать, проверяя счетчик производительности Ожидаемый срок службы страницы .
Исключение записей в кэше приводит к тому, что в следующий раз, когда потребуется удалить запись (будь то скомпилированный план, токен доступа или что-то еще), ее нужно создавать с нуля, что приводит к увеличению потребления ЦП, памяти и операций ввода-вывода. эффект, который может проявиться даже после завершения длительных запросов.
Теперь может случиться так, что в вашей системе установлены такие огромные объемы ОЗУ, что сканирование нескольких больших таблиц не имеет значения, ваша ОЗУ может вместить всю вашу базу данных с запасом места. В этом случае нет проблем. Но в большинстве случаев это не так.
IO
Это связано с пунктом выше (ПАМЯТЬ). Все эти прочитанные страницы, чтобы удовлетворить сканирование индекса, должны быть перенесены в память, что означает (потенциально большую часть) пропускной способности ввода-вывода, потребляемой долго выполняющимися запросами. Кроме того, все грязные страницы данных, которые удаляются из пула буферов, должны быть записаны на диск, что приводит к увеличению количества операций ввода-вывода. И чистые страницы, которые были выселены, вероятно, понадобятся когда-нибудь в будущем, так что даже больше IO.
Если IO, сгенерированный сканированием, превышает пропускную способность вашей системы, операции IO начинают ставиться в очередь на контроллере (дисках) диска. это легко проверить в счетчиках производительности Physical Disk / Avg Queue Length .
Соперничество
И, наконец, самая большая проблема 1043 *: конфликт блокировок. Как объяснено, параллельные запросы почти всегда подразумевают сканирование таблицы. А при сканировании таблиц используется общая блокировка для каждого посещаемого ряда. Это правда, что они снимают блокировку, как только запись читается в обычном рабочем режиме, но все же вы гарантированно будете запрашивать блокировку S для каждой строки в таблице, Это в значительной степени гарантирует, что эти сканы попадут в строку, заблокированную X обновлением. Когда это происходит, сканирование должно быть остановлено и ждать, пока не будет снята блокировка X, что происходит, когда транзакции обновления, наконец, фиксируются. В результате даже умеренная активность OLTP в таблице блокирует длительные запросы. В идеале это все, что происходит, и в результате просто плохая производительность. Но все может стать ужасно быстро, если длительный запрос делает что-то причудливое, например получение блокировок страницы вместо блокировок строк. Поскольку эти сканирования проходят сквозные индексы и они гарантированно вступают в конфликт с обновлениями, блокировки более высокой степени детализации, полученные этими запросами, больше не конфликтуют только с блокировками обновлений, но фактически приводят к взаимным блокировкам. Объяснение того, как это может произойти, выходит за рамки этого ответа.
Чтобы устранить конфликт, когда запросы законно делают полное сканирование, лучшая альтернатива - использовать магический снимок: либо снимки базы данных , созданные для создания отчетов, либо использование Снимок изоляции уровней. Обратите внимание, что некоторые могут порекомендовать использовать грязное чтение, но я пока не нашел случая, когда это было действительно приемлемо.