SQL Server 简单插入语句超时
Posted
技术标签:
【中文标题】SQL Server 简单插入语句超时【英文标题】:SQL Server simple Insert statement times out 【发布时间】:2010-10-01 14:58:53 【问题描述】:我有一个有 6 列的简单表格。大多数情况下,任何插入语句都可以正常工作,但有时我会遇到 DB Timeout 异常: 超时已过。在操作完成之前超时时间已过或服务器没有响应。声明已终止。
超时设置为 10 秒。
我应该提到我正在使用 NHibernate,并且该语句还在插入本身之后包含一个“select SCOPE_IDENTITY()”。
我的想法是该表被锁定或其他什么,但当时该表上没有其他语句运行。
所有的插入都非常简单,在 sql profiler 中一切看起来都很正常,表没有索引,只有 PK(页面填充度:98.57 %)。
关于我应该寻找什么的任何想法?
谢谢。
【问题讨论】:
【参考方案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。以上是关于SQL Server 简单插入语句超时的主要内容,如果未能解决你的问题,请参考以下文章