【问题标题】:SQL Server lock/hang issueSQL Server 锁定/挂起问题
【发布时间】:2010-06-10 12:47:20
【问题描述】:

我在 Windows Server 2008 R2 上使用 SQL Server 2008,一切正常。

我偶尔会遇到 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 表添加命中轨道,它非常简单,它只是从传入的参数中构建一个字符串,其中涉及从一些查找表中进行一些选择,然后是主插入:

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

ContentHit 表的 ID 列上有一个聚集索引,我在 CreatedDate 上添加了另一个索引,因为它在选择中使用。

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

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

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

编辑 2: 我检查了执行计划,查询看起来很合理。正如我之前所说,当它运行时只需要大约 200 毫秒即可执行。我在 select 语句中添加了 MAXDOP 1 以强制它只使用一个 CPU 内核,但我仍然看到了这个问题。当我查看等待时间时,我发现 XE_DISPATCHER_WAIT、ONDEMAND_TASK_QUEUE、BROKER_TRANSMITTER、KSOURCE_WAKEUP 和 BROKER_EVENTHANDLER 占用了大量的等待时间。

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

【问题讨论】:

  • 听起来很奇怪,你用探查器检查过 Subsonic 是做什么的吗? SP 的调用方式与您手动调用的方式完全相同吗?
  • 尝试将命中的内容中的数据拖到临时表中,然后对加入其他表的内容进行完整查询。

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


【解决方案1】:

问题可能是并发,而不是锁定。 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 等待指示)。

另外,看看这篇论文:Performance tuning with wait statistics。它很好地总结了不同的等待类型及其对性能的影响。

附:在查询之前使用 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 比向每个表添加 (nolock) 更容易。

【讨论】:

  • 我同意这个答案。尝试调整最大并行度。具有讽刺意味的是,我见过降低最大dop可以提高性能的情况。
  • 好的,谢谢,我将开始研究 MAXDOP 并了解更多关于当 CPU 处于 100% 时会发生什么的信息。
  • MostPopularRead 一旦调用就被缓存,所以不应该经常调用。但是,由于这个问题,当站点等待 MostPopularRead 执行以便它可以被缓存时,加载更多请求进入并触发存储过程 - 这是 SQL Server 挂起的时候。如果我从管理工作室手动运行存储过程,它永远不会超过 0.5 秒,通常大约 200 毫秒。
【解决方案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 线程池工作项的线程。由于他们大部分时间都花在停车和等待上,因此他们被认为是不切实际的等待时间。忽略它们。

【讨论】:

  • 谢谢莱姆斯。但正如我之前所说,当我运行查询时,它的运行效率非常高(200 毫秒),除非它挂起,所以我不希望使用不同的索引来解决这个问题。您添加的索引是我添加到该表的索引。如果我的 Subsonic ORM 测试没有显示任何内容,我会发布此信息。
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

    默认情况下,sql server 使用所有核心/cpu 进行所有查询(max DoP 设置> 高级属性,DoP= 并行度),即使实际上只有一个核心在等待一些 I /O.
    如果您搜索网络或此站点,您会发现比我解释得更好的资源(例如监控您的 I/O,尽管您看到了 CPU 绑定问题)。
    在一台服务器上,我们无法使用锁定所有资源 (CPU) 的错误查询来更改应用程序,但是通过将 DoP 设置为内核数的一半,我们设法避免服务器“停止”。在我们的案例中,对查询并行度较低的影响可以忽略不计。

    --
    多姆

    【讨论】:

      【解决方案5】:

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

      最终我们没时间解决这个谜团——我们找到了一种更有效的方法来收集这些信息并将其缓存在数据库中,这样就解决了我们的问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多