Производительность SQL Server с множеством одновременных и длительных запросов - PullRequest
10 голосов
/ 16 июля 2009

Мне интересно, как одновременное выполнение многих длительных запросов повлияет на способность SQL Server своевременно обслуживать каждый запрос.

[Изменить]

Я не хотел быть расплывчатым, это скорее гипотетически. Давайте просто предположим, что запросы представляют собой операторы select с неким предикатом для таблиц с миллионами строк.

Ответы [ 5 ]

26 голосов
/ 16 июля 2009

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 в таблице блокирует длительные запросы. В идеале это все, что происходит, и в результате просто плохая производительность. Но все может стать ужасно быстро, если длительный запрос делает что-то причудливое, например получение блокировок страницы вместо блокировок строк. Поскольку эти сканирования проходят сквозные индексы и они гарантированно вступают в конфликт с обновлениями, блокировки более высокой степени детализации, полученные этими запросами, больше не конфликтуют только с блокировками обновлений, но фактически приводят к взаимным блокировкам. Объяснение того, как это может произойти, выходит за рамки этого ответа.

Чтобы устранить конфликт, когда запросы законно делают полное сканирование, лучшая альтернатива - использовать магический снимок: либо снимки базы данных , созданные для создания отчетов, либо использование Снимок изоляции уровней. Обратите внимание, что некоторые могут порекомендовать использовать грязное чтение, но я пока не нашел случая, когда это было действительно приемлемо.

2 голосов
/ 16 июля 2009

Я бы использовал план выполнения , чтобы узнать об оптимизации запросов. Также вы должны знать, что они могут блокировать строки или таблицы, если они занимают длительный период времени. Чтобы ответить на этот вопрос, вы должны принять во внимание, сколько памяти и ресурсов процессора может обрабатывать ваш sql-сервер. Тестирование в среде разработки даст вам хорошее представление о том, что произойдет, чем дольше будут выполняться запросы, тем больше ресурсов будет использовано, и они могут стать узким местом для всей вашей системы.

1 голос
/ 16 июля 2009

Трудно сказать.

  • Массивные параллельные запросы?
  • Тысячи маленьких?
  • OLTP или склад?
  • Процессор или IO или память связаны?
  • Серверное оборудование и настройки? MAXDOP, RAID и т. Д.
  • Тот же набор данных? (в пуле буферов или большом количестве данных в памяти)

У нас есть 100 миллионов таблиц строк с агрегированными запросами менее 1 секунды, которые выполняются много раз в рабочее время, и 10 000 запросов к таблицам строк, которые занимают 20 секунд, но выполняются только один раз в 4 часа утра.

0 голосов
/ 16 июля 2009

Производительность обычно линейно ухудшается, если только вы не начнете сталкиваться с серьезными проблемами ввода-вывода.

Тем не менее, доказательство заключается в тестировании ваших запросов по отдельности и параллельно, а также в отслеживании статистики SQL Server.

0 голосов
/ 16 июля 2009

очевидно, чем больше запросов запущено, тем медленнее будет производительность.

степень будет зависеть от данных и типа запросов (обновления / удаления / вставки?).

запросы, которые блокируют таблицы, могут быть особенно проблематичными; использование nolock, где это уместно, может улучшить производительность.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...