Проблема блокировки / зависания SQL Server - PullRequest
2 голосов
/ 10 июня 2010

Я использую SQL Server 2008 на Windows Server 2008 R2, все запущено.

Время от времени возникают проблемы с зависанием SQL Server при 100% загрузке ЦП на нашем работающем сервере. Кажется, что все время ожидания SQL Server, когда это происходит, передается SOS_SCHEDULER_YIELD.

Вот сохраненный процесс, который вызывает зависание. Я добавил «WITH (NOLOCK)» в попытке исправить то, что кажется проблемой блокировки.

ALTER PROCEDURE [dbo].[MostPopularRead]
AS
BEGIN
SET NOCOUNT ON;

SELECT 
    c.ForeignId , ct.ContentSource as ContentSource
    , sum(ch.HitCount * hw.Weight) as Popularity
    , (sum(ch.HitCount * hw.Weight) * 100) / @Total as Percent
    , @Total as TotalHits
from 
    ContentHit ch WITH (NOLOCK)
    join [Content] c WITH (NOLOCK) on ch.ContentId = c.ContentId
    join HitWeight hw WITH (NOLOCK) on ch.HitWeightId = hw.HitWeightId
    join ContentType ct WITH (NOLOCK) on c.ContentTypeId = ct.ContentTypeId
where 
    ch.CreatedDate between @Then and @Now
group by
    c.ForeignId , ct.ContentSource
order by
    sum(ch.HitCount * hw.HitWeightMultiplier) desc
END

Хранимая процедура считывает данные из таблицы «ContentHit», которая представляет собой таблицу, которая отслеживает щелчок по контенту на сайте (он попадает довольно часто - от 4 до 20 посещений в минуту). Таким образом, довольно ясно, что эта таблица является источником проблемы. Существует хранимый процесс, который вызывается для добавления треков попаданий в таблицу ContentHit, это довольно тривиально, он просто создает строку из переданных параметров, которая включает в себя несколько выборок из некоторых таблиц поиска, за которыми следует основная вставка:

BEGIN TRAN
insert into [ContentHit] 
    (ContentId, HitCount, HitWeightId, ContentHitComment)
values
    (@ContentId, isnull(@HitCount,1), isnull(@HitWeightId,1), @ContentHitComment)
COMMIT TRAN

Таблица ContentHit имеет кластеризованный индекс в столбце идентификатора, и я добавил еще один индекс для CreatedDate, поскольку он используется в select.

Когда я профилирую проблему, я вижу, что сохраненный процесс выполняется ровно 30 секунд, затем возникает исключение тайм-аута SQL. Если это имеет значение, то веб-приложение, использующее его, является ASP.NET, и я использую Subsonic (3) для выполнения этих сохраненных процедур.

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

EDIT: Хранимый процесс MostPopularRead вызывается очень редко - он вызывается на главной странице сайта, но результаты кэшируются на день. Шаблон событий, которые я наблюдаю, - это когда я очищаю кеш, несколько запросов приходят на домашний сайт, и все они обращаются к сохраненному процессу, потому что он еще не был кэширован. После этого SQL Server достигает максимума и может быть разрешен только путем перезапуска процесса SQL Server. Когда я делаю это, процесс обычно выполняется ОК (примерно через 200 мс) и помещает данные обратно в кеш.

РЕДАКТИРОВАТЬ 2: Я проверил план выполнения, и запрос выглядит вполне обоснованным. Как я уже говорил ранее, когда он запускается, для его выполнения требуется всего около 200 мс. Я добавил MAXDOP 1 в оператор SELECT, чтобы заставить его использовать только одно ядро ​​ЦП, но я все еще вижу проблему. Когда я смотрю на время ожидания, я вижу, что XE_DISPATCHER_WAIT, ONDEMAND_TASK_QUEUE, BROKER_TRANSMITTER, KSOURCE_WAKEUP и BROKER_EVENTHANDLER занимают огромное количество времени ожидания.

РЕДАКТИРОВАТЬ 3: Раньше я думал, что это связано с Subsonic, нашим ORM, но, переключившись на ADO.NET, ошибка все еще активна.

Ответы [ 5 ]

3 голосов
/ 10 июня 2010

Проблема, скорее всего, в параллелизме, а не в блокировке. SOS_SCHEDULER_YIELD возникает, когда задача добровольно предоставляет планировщик для выполнения других задач. Во время этого ожидания задача ожидает обновления кванта .

Как часто вызывается [MostPopularRead] SP и сколько времени занимает выполнение? Агрегация в вашем запросе может быть довольно загруженной процессором, особенно если имеется много данных и / или неэффективных индексов. Таким образом, вы можете столкнуться с высокой нагрузкой на процессор - в основном, спрос на процессорное время слишком высок.

Я бы рассмотрел следующее:

  1. Проверьте, какие другие запросы выполняются, когда процессор загружен на 100%? Посмотрите на sys.dm_os_waiting_tasks, sys.dm_os_tasks, sys.dm_exec_requests.

  2. Посмотрите на план запроса [MostPopularRead], попробуйте оптимизировать запрос. Нередко неэффективный запрос является основной причиной проблем с производительностью, и оптимизация запросов гораздо проще, чем другие методы повышения производительности.

  3. Если план запроса параллельный и запрос часто вызывается несколькими клиентами одновременно, может помочь принудительное использование однопотокового плана с подсказкой MAXDOP = 1 (обильное использование параллельных планов обычно указывается SOS_SCHEDULER_YIELD, а CXPACKET ожидает ).

Также посмотрите на эту статью: Настройка производительности со статистикой ожидания . Это дает довольно хорошее резюме различных типов ожидания и их влияния на производительность.

P.S. Проще использовать SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED перед запросом, вместо добавления (nolock) к каждой таблице.

2 голосов
/ 10 июня 2010

Удалите подсказку NOLOCK .

Откройте запрос в SSMS, запустите SET STATISTICSIO ON и выполните запрос в процедуре.Дайте ему закончить и опубликуйте здесь сообщения статистики IO.Затем опубликуйте определения таблиц и все индексы, определенные для них.Тогда кто-нибудь сможет ответить с нужными индексами, которые вам нужны.

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

Предполагаемый индекс покрытия будет:

create index ContentHitCreatedDate 
   on ContentHit (CreatedDate) 
   include (HitCount, ContentId,  HitWeightId);

Обновление

XE_DISPATCHER_WAIT, ONDEMAND_TASK_QUEUE, BROKER_TRANSMITTER, KSOURCE_WAKEUPи BROKER_EVENTHANDLER: вы можете спокойно игнорировать все эти ожидания.Они появляются, потому что они представляют потоки, припаркованные и ожидающие отправки рабочих элементов XEvents, Service Broker или внутреннего пула потоков SQL.Поскольку они проводят большую часть своего времени на стоянке и в ожидании, им приходится учитывать нереальные времена ожидания.Игнорировать их.

0 голосов
/ 13 августа 2010

Спасибо всем, кто написал, я получил несколько отличных советов по настройке SQL Server.

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

0 голосов
/ 10 июня 2010

По умолчанию сервер sql использует все ядро ​​/ процессор для всех запросов (максимальная настройка DoP> расширенное свойство, DoP = степень параллелизма), что может привести к 100% -ной загрузке ЦП, даже если какое-то I действительно ожидает только одно ядро./O.
Если вы будете искать в сети или на этом сайте, вы найдете ресурс, объясняющий это лучше, чем я (например, мониторинг вашего ввода-вывода, несмотря на то, что вы видите проблему с процессором).
На одном сервере мы не смоглиизмените приложение с неверным запросом, который заблокировал все ресурсы (ЦП), но установив DoP равным половине числа ядер, нам удалось избежать «остановки» сервера.В нашем случае влияние на менее параллельные запросы было незначительным.

-
Dom

0 голосов
/ 10 июня 2010

Если вы считаете ContentHit источником вашей проблемы, вы можете добавить Индекс покрытия

CREATE INDEX IX_CONTENTHIT_CONTENTID_HITWEIGHTID_HITCOUNT 
  ON dbo.ContentHit (ContentID, HitWeightID, HitCount)

Взгляните на план запросов , если хотите быть уверенным в узком месте в своем запросе.

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