我们有一个存储过程,运行正常,直到10分钟前,然后它只是在你调用后挂起。
观察:
还有什么可以继续?
更新:我猜它与参数嗅探有关。我使用Adam Machanic的例程来找出哪个子查询挂起。由于Martin Smith的提示,我发现查询计划出了问题。我了解了SP中的子查询EXEC ... WITH RECOMPILE
,OPTION(RECOMPILE)
和OPTION (OPTIMIZE FOR (@parameter = 1))
,以便攻击参数嗅探。我仍然不知道在这个特殊情况下出了什么问题,但是我从这场战斗中走出来,经验丰富,武装得更好。我知道下次该做什么。所以这就是要点!
答案 0 :(得分:16)
我认为这与参数嗅探有关,需要将输入参数参数化为SP中的本地参数。通过重新编译添加会导致重新创建执行计划,并消除了拥有SP的许多好处。我们在许多报告中使用With Recompile试图消除这个悬而未决的问题,偶尔会导致挂起可能与同时访问同一个表的其他锁和/或事务有关的SP。有关详细信息,请参阅此链接 Parameter Sniffing (or Spoofing) in SQL Server并将您的SP更改为以下内容以解决此问题:
CREATE PROCEDURE [dbo]。[SPNAME] @ p1 int,@ p2 int AS
DECLARE @ localp1 int,@ localp2 int
SET @ localp1 = @ p1 SET @ localp2 = @ p2
答案 1 :(得分:11)
在查询运行时运行Adam Machanic的优秀sp_WhoIsActive存储过程。它会给你等待信息 - 意思是,存储过程正在等待什么 - 加上执行计划之类的东西:
http://www.brentozar.com/archive/2010/09/sql-server-dba-scripts-how-to-find-slow-sql-server-queries/
答案 2 :(得分:1)
当我们添加新数据时,执行计划有时会变得无效或过时,那么存储过程就会开始进入这个不确定的阶段。在数据库上运行以下命令
DBCC DROPCLEANBUFFERS
DBCC FREEPROCCACHE
下次运行存储过程时,它将刷新高速缓存并重建执行计划。
答案 3 :(得分:0)
感谢所有评论。
我仍然没有找到答案,但我会在这里发布进度。
之前我没有重现这个问题,但是今天我偶然发现了另一个存在同样问题的存储过程。再次出现相同的症状:
使用上面的提示,我找到了SP执行计划,它没有显示任何异常(对我来说,至少)。创建具有相同内容的新存储过程也不能解决问题。所以我开始将SP剥离到越来越少的内容,直到我遇到 UDF调用另一个数据库。当我删除它(用函数的内联内容替换调用,CASE
语句)时,它再次运行正常。
所以这可能是问题所在,但我不太确定,因为上次问题本身就消失了,而且在剥离这个SP时我也改变了很多其他的东西。
答案 4 :(得分:0)
我想我遇到了同样的问题。我从子查询中删除了参数。之后它运行得很好。不确定你的脚本是否可以这样做,但这就是为我解决的问题。
答案 5 :(得分:0)
首先,第一件事。
请检查是否有任何未提交的交易。没有“COMMIT TRANSACTION”的开始交易
答案 6 :(得分:0)
答案Brent Ozar可能有效,但是默认情况下它仅返回活动的命令文本。例如,对于以下查询,它返回WAITFOR DELAY '00:00:05'
:
CREATE PROCEDURE spGetChangeNotifications
AS
BEGIN
SET NOCOUNT ON;
DECLARE
@actionType TINYINT;
WHILE @actionType IS NULL
BEGIN
WAITFOR DELAY '00:00:05';
SELECT TOP 1
@actionType = [ActionType]
FROM
TableChangeNotifications;
END;
SELECT
TOP 1000 [RecordID], [Component], [TableName], [ActionType], [Key1], [Key2], [Key3]
FROM
TableChangeNotifications;
END;
外观如何:
因此,按照here所述检查参数@get_outer_command
。
另外,请尝试使用此方法(MS Docs中稍作修改的过程):
DECLARE
@sessions TABLE
(
[SPID] INT,
STATUS VARCHAR(MAX),
[Login] VARCHAR(MAX),
[HostName] VARCHAR(MAX),
[BlkBy] 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 @sessions
EXEC sp_who2;
SELECT
[req].[session_id],
[A].[Login] AS 'login',
[A].[HostName] AS 'hostname',
[req].[start_time],
[cpu_time] AS 'cpu_time_ms',
OBJECT_NAME([st].[objectid], [st].[dbid]) AS 'object_name',
SUBSTRING(REPLACE(REPLACE(SUBSTRING([ST].text, ([req].[statement_start_offset] / 2) + 1, ((CASE [statement_end_offset]
WHEN -1
THEN DATALENGTH([ST].text)
ELSE [req].[statement_end_offset]
END - [req].[statement_start_offset]) / 2) + 1), CHAR(10), ' '), CHAR(13), ' '), 1, 512) AS [statement_text],
[ST].text AS 'full_query_text'
FROM
sys.dm_exec_requests AS req
CROSS APPLY
sys.dm_exec_sql_text(req.sql_handle) AS ST
LEFT JOIN @sessions AS A
ON A.SPID = req.session_id
ORDER BY
[cpu_time] DESC;
外观如何:
当然,可以从Brent Ozar
答案中修改code,因此也可以选择完整的查询文本。选择了几乎相同的技术there(代码链接为18.07.2020,因此可能会随时间而改变):