【问题标题】:SQL Server simple Insert statement times outSQL Server 简单插入语句超时
【发布时间】:2010-10-01 14:58:53
【问题描述】:

我有一个有 6 列的简单表格。大多数情况下,任何插入语句都可以正常工作,但有时我会遇到 DB Timeout 异常: 超时已过。在操作完成之前超时时间已过或服务器没有响应。声明已终止。

超时设置为 10 秒。

我应该提到我正在使用 NHibernate,并且该语句还在插入本身之后包含一个“select SCOPE_IDENTITY()”。

我的想法是该表被锁定或其他什么,但当时该表上没有其他语句运行。

所有的插入都非常简单,在 sql profiler 中一切看起来都很正常,表没有索引,只有 PK(页面填充度:98.57 %)。

关于我应该寻找什么的任何想法?

谢谢。

【问题讨论】:

    标签: sql sql-server database nhibernate timeout


    【解决方案1】:

    查看表格的碎片,您可能会因此而出现页面拆分

    【讨论】:

      【解决方案2】:

      当时没有其他语句在该表上运行。

      作为事务的一部分针对其他表运行的语句呢?这可能会在问题表上留下锁。

      还要检查当时发生的日志文件或数据文件增长情况,如果您运行的是 SQL2005,它会显示在 SQL 错误日志中。

      【讨论】:

      • 其实事务插入到3张表中,怎么会锁问题表呢?
      • 这样,大致:0:开始交易; 1:更新问题表中的一条记录(运行快); 2:更新一些其他表(需要很长时间); 3:提交问题表会一直锁定到第3步;如果另一个作业尝试更新被锁定的记录,它将等待。
      【解决方案3】:

      我认为您最有可能的罪魁祸首是来自另一个事务的阻塞锁(或者可能来自触发器或幕后的其他东西)。

      最简单的判断方法是启动INSERT,当它挂起时,在同一服务器上的另一个窗口中运行EXEC SP_WHO2。这将列出所有当前的数据库活动,并有一个名为BLK 的列,它将显示当前是否有任何进程被阻止。检查挂起连接的SPID,看看BLK 列中是否有任何内容,如果有,那就是阻止你的进程。

      即使您认为没有任何其他语句在运行,唯一确定的方法是使用类似的 SP 列出当前事务。

      【讨论】:

      • 如果超时偶尔发生,我无法“捕捉”运行调试命令的时间?
      • 如何停止阻塞的进程?
      • 我想如果您的超时时间为 10 秒,您可以在 8 或 9 秒后运行 SP_WHO2(请参阅其他答案),看看它是否捕捉到了什么。这可能很难实现,但可能是唯一的方法。当然,如果它成功了,你会在它开始之前取消它。
      【解决方案4】:

      可能是表格需要很长时间才能增长。

      如果您将表设置为大幅增长,并且没有启用即时文件初始化,那么查询肯定会每隔一段时间就会超时。

      看看这个烂摊子:MSDN

      【讨论】:

      • 自动增长设置为 1MB,分配 1MB 需要这么长时间吗?
      • @meidan 不,它不会花费那么长时间,但我会将其更改为以更大的块增长,否则随着时间的推移,如果文件系统不断增长,您最终会得到一个非常碎片化的文件系统。默认值为 10%,这适用于除了非常大的数据库之外的大多数情况。
      • @Eam - 坦克!它对插入大对象非常重要
      【解决方案5】:

      我们的 QA 有一些返回大结果集的 Excel 连接,这些查询因 WaitType 为 ASYNC_NETWORK_IO 而暂停了一段时间。在此期间,所有其他查询都超时,因此特定插入与它无关。

      【讨论】:

        【解决方案6】:

        这个问题似乎是一个代码 sn-p 的好地方,我用它来查看阻塞和阻塞查询的实际 SQL 文本。

        下面的 sn-p 采用 SP_WHO2 返回“.”的约定。 BlockedBy 的文本用于非阻塞查询,因此它会将它们过滤掉并返回剩余查询的 SQL 文本(“受害者”和“罪魁祸首”):

        --prepare a table so that we can filter out sp_who2 results
        DECLARE @who TABLE(BlockedId INT, 
                           Status VARCHAR(MAX), 
                           LOGIN VARCHAR(MAX), 
                           HostName VARCHAR(MAX), 
                           BlockedById VARCHAR(MAX), 
                           DBName VARCHAR(MAX), 
                           Command VARCHAR(MAX), 
                           CPUTime INT, 
                           DiskIO INT, 
                           LastBatch VARCHAR(MAX), 
                           ProgramName VARCHAR(MAX), 
                           SPID_1 INT, 
                           REQUESTID INT)
        INSERT INTO @who EXEC sp_who2
        
        --select the blocked and blocking queries (if any) as SQL text
        SELECT 
        (
            SELECT TEXT 
            FROM sys.dm_exec_sql_text(
               (SELECT handle 
                FROM (
                    SELECT CAST(sql_handle AS VARBINARY(128)) AS handle
                    FROM sys.sysprocesses WHERE spid = BlockedId
                ) query)
            )
        ) AS 'Blocked Query (Victim)',
        (
            SELECT TEXT 
            FROM sys.dm_exec_sql_text(
               (SELECT handle 
                FROM (
                    SELECT CAST(sql_handle AS VARBINARY(128)) AS handle
                    FROM sys.sysprocesses WHERE spid = BlockedById
                ) query)
            )
        ) AS 'Blocking Query (Culprit)'
        FROM @who 
        WHERE BlockedById != '  .'
        

        【讨论】:

        • 老鼠。在 SQL 2000 中,'MAX' 附近的语法不正确,插入表变量时不能将 EXECUTE 用作源等。此脚本需要什么版本的 SQL? 它确实适用于 SQL 2008 年,但那个数据库不是我的问题。
        • 您是否尝试过使用临时表而不是表变量?
        • 对完全无用的评论表示歉意,但是……干得好那个人:) 这是名人堂的剧本。帮助我解决了一个困扰我们一个系统很长时间的问题。 +1000
        • 哇,这是一个地狱般的查询,魔术。一个我会永远坚持下去的sn-p。
        猜你喜欢
        • 2015-09-21
        • 1970-01-01
        • 2012-03-19
        • 2011-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-28
        相关资源
        最近更新 更多