存储过程看起来似乎没有解释

时间:2010-10-15 16:09:42

标签: tsql sql-server-2008 stored-procedures

我们有一个存储过程,运行正常,直到10分钟前,然后它只是在你调用后挂起。

观察:

  • 将代码复制到查询窗口中会产生1秒的查询结果
  • SP采取>我取消它2.5分钟
  • 活动监视器显示它没有被任何东西阻挡,它只是在做一个SELECT。
  • 在SP上运行sp_recompile无济于事
  • 删除并重新创建SP无济于事
  • 将LOCK_TIMEOUT设置为1秒无效

还有什么可以继续?


更新:我猜它与参数嗅探有关。我使用Adam Machanic的例程来找出哪个子查询挂起。由于Martin Smith的提示,我发现查询计划出了问题。我了解了SP中的子查询EXEC ... WITH RECOMPILEOPTION(RECOMPILE)OPTION (OPTIMIZE FOR (@parameter = 1)),以便攻击参数嗅探。我仍然不知道在这个特殊情况下出了什么问题,但是我从这场战斗中走出来,经验丰富,武装得更好。我知道下次该做什么。所以这就是要点!

7 个答案:

答案 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

下次运行存储过程时,它将刷新高速缓存并重建执行计划。

msdn.microsoft.com

答案 3 :(得分:0)

感谢所有评论。

我仍然没有找到答案,但我会在这里发布进度。

之前我没有重现这个问题,但是今天我偶然发现了另一个存在同样问题的存储过程。再次出现相同的症状:

  • 挂起的查询在正常查询窗口(用sp_whoisactive标识的悬挂件)中运行正常且快速(3秒)
  • 没有锁,根据Activity Monitor SPID正在执行SELECT
  • 存储过程运行超过6小时而无响应
  • 传递给SP的参数和在窗口中声明的变量是相同的

使用上面的提示,我找到了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;

外观如何:

How it looks like #1

因此,按照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;

外观如何:

How it looks like #2

当然,可以从Brent Ozar答案中修改code,因此也可以选择完整的查询文本。选择了几乎相同的技术there(代码链接为18.07.2020,因此可能会随时间而改变):

Code part from amachanic Git repo