Я использую 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, ошибка все еще активна.