SQL Server锁定/挂起问题

时间:2010-06-10 12:47:20

标签: sql-server performance sql-server-2008 locking subsonic3

我在Windows Server 2008 R2上使用的是SQL Server 2008,全部都是spd。

我偶尔会遇到SQL Server挂起问题,我的实时服务器上的CPU占用率为100%。似乎所有在SQL Sever上等待的时间都发生在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表添加命中轨道,它非常简单,它只是从传入的参数中构建一个字符串,其中包含一些查找表中的一些选择,然后是主插入:< / p>

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

ContentHit表在其ID列上有一个聚簇索引,我在CreatedDate上添加了另一个索引,因为它在select中使用。

当我描述问题时,我看到存储过程执行了30秒,然后发生SQL超时异常。如果它有所作为,使用它的Web应用程序是ASP.NET,我使用Subsonic(3)来执行这些存储过程。

有人可以告诉我如何才能最好地解决这个问题?我不在乎阅读脏数据......

编辑: MostPopularRead存储过程很少被调用 - 它在站点的主页上调用,但结果缓存了一天。我看到的事件模式是当我清除缓存时,多个请求进入主站点,并且它们都点击存储过程,因为它尚未被缓存。 SQL Server然后最大化,并且只能通过重新启动sql server进程来解决。当我这样做时,proc通常会执行OK(大约200毫秒)并将数据放回缓存中。

编辑2: 我检查了执行计划,查询看起来很合理。正如我之前所说,它运行时只执行约200ms。我已经将MAXD​​OP 1添加到select语句中以强制它只使用一个CPU内核,但我仍然看到了这个问题。当我看到等待时间时,我看到XE_DISPATCHER_WAIT,ONDEMAND_TASK_QUEUE,BROKER_TRANSMITTER,KSOURCE_WAKEUP和BROKER_EVENTHANDLER占用了大量的等待时间。

编辑3: 我以前认为这与我们的ORM Subsonic有关,但是切换到ADO.NET后,错误仍然存​​在。

5 个答案:

答案 0 :(得分:3)

问题可能是并发,而不是锁定。当任务自愿生成调度程序以执行其他任务时,会发生SOS_SCHEDULER_YIELD 。在此等待期间,任务正在等待续订其量程

多长时间调用[MostPopularRead] SP以及执行需要多长时间? 查询中的聚合可能是CPU密集型的,尤其是在存在大量数据和/或无效索引的情况下。因此,您最终可能会遇到高CPU压力 - 基本上,对CPU时间的需求太高。

我会考虑以下事项:

  1. 检查CPU 100%忙时正在执行的其他查询?查看sys.dm_os_waiting_tasks,sys.dm_os_tasks,sys.dm_exec_requests。

  2. 查看[MostPopularRead]的查询计划,尝试优化查询。通常,无效的查询是性能问题的根本原因,查询优化比其他性能改进技术简单得多。

  3. 如果查询计划是并行的并且查询通常由多个客户端同时调用,则强制使用MAXDOP = 1提示的单线程计划可能会有所帮助(并行计划的大量使用通常由SOS_SCHEDULER_YIELD和CXPACKET等待指示)。

  4. 另外,请看一下这篇论文:Performance tuning with wait statistics。它给出了不同等待类型及其对性能影响的非常好的总结。

    P.S。在查询之前使用SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED更容易,而不是向每个表添加(nolock)。

答案 1 :(得分:2)

Remove the NOLOCK hint

在SSMS中打开查询,运行SET STATISTICSIO ON并在过程中运行查询。让它完成并发布IO统计信息。然后发布表定义及其上定义的所有索引。然后有人可以使用您需要的正确索引进行回复。

与所有SQL性能问题一样,如果没有完整的模式定义,查询的文本在很大程度上是无关紧要的。

猜测覆盖指数将是:

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

更新

XE_DISPATCHER_WAITONDEMAND_TASK_QUEUEBROKER_TRANSMITTERKSOURCE_WAKEUPBROKER_EVENTHANDLER:您可以安全地忽略所有这些等待。它们出现是因为它们表示停放的线程并等待分派XEvents,Service Broker或内部SQL线程池工作项。由于他们花费大部分时间停泊和等待,他们被计入不切实际的等待时间。忽略它们。

答案 2 :(得分:0)

如果您认为ContentHit是问题的根源,可以添加Covering Index

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

如果您想确定查询中的瓶颈,请查看Query Plan

答案 3 :(得分:0)

默认设置sql server使用所有核心/ cpu进行所有查询(最大DoP设置&gt;高级属性,DoP =并行度),即使只有一个核心实际等待某些核心,也可以导致100%CPU / O。
如果你搜索网络或这个网站,你会发现资源比我更好地解释它(比如监视你的I / O,尽管你看到一个CPU限制的问题)。
在一台服务器上,我们无法使用锁定所有资源(CPU)的错误查询来更改应用程序,而是将DoP设置为我们设法避免服务器“停止”的核心数量的一半。在我们的案例中,对查询不太平行的影响可以忽略不计。

-
DOM

答案 4 :(得分:0)

感谢所有发布的人,我得到了一些很棒的SQL Server性能调优技巧。

最后我们花了很多时间来解决这个谜团 - 我们找到了一种更有效的方法来收集这些信息并将其缓存在数据库中,所以这解决了我们的问题。