SQL Server 中的性能问题。在我的场景中是否进行参数嗅探?

Ale*_*sko 3 performance sql-server stored-procedures sql-server-2017 parameter-sniffing

在这里,我面临着存储过程中的特定语句出现的性能问题,该存储过程有时有很多语句

SP 每秒执行一次,通常完成时间不到 50 毫秒,但在出现问题时(可能每月一次,或每周几次 - 随机)要长得多,直到重新编译

SP有2个输入参数
SP供不同的应用使用

每个语句通常在约 1 毫秒内完成,但在出现问题时需要更长的时间

我必须承认我对什么是参数嗅探以及如何修复它只有初学者的了解。
绝对应该在教育上投入更多的时间,但在我的国家发生的所有事情都很难做到,请不要对我太严格

最常出现问题的一种说法:

UPDATE MyTable SET tMax = 0 
      WHERE tMax = 1
      and tID in (SELECT b8 FROM #e538)
Run Code Online (Sandbox Code Playgroud)

在出现问题时,此更新语句有大量 LCK_M_U 等待,并开始与从不同会话执行的完全相同的语句发生死锁

另外两个说法:

INSERT #e534 (b4, d4, s4, r4)
SELECT tID, tDate, tStatusID, ID
FROM MyTable
WHERE tStatusID = (SELECT min(tStatusID) 
                    FROM MyTable as f, LMyTable 
                    WHERE tID = MyTable.tID 
                          and tType = 1 
                          and ltID = tStatusID 
                          and ltComplete = 1 AND tActive = 1)
and tID in (select b8 from #e538)
AND tActive = 1
Run Code Online (Sandbox Code Playgroud)

INSERT #e534 (b4, d4, s4, r4)
SELECT tID, tDate, tStatusID, ID
FROM MyTable
WHERE (tDate = (SELECT top 1 tDate 
                 FROM MyTable as f 
                 WHERE tID = MyTable.tID 
                 and tType = 1 
                 AND tActive = 1 
                 order by tDate desc))
and tType  = 1
AND tActive = 1
and tID in (select b8 from #e538)
Run Code Online (Sandbox Code Playgroud)

当比较“好”与“坏”计划时,执行计划肯定是非常不同的,我可以看到 fromCXPACKETCXCONSUMER等待这些语句,而通常没有任何语句

不幸的是,我没有“坏”执行计划,因为监控工具说“没有为此查询采样查询计划”。

MyTable 有 225+ 百万行,tID 是聚集索引键(BIGINT,虽然不是唯一的)

这是我的问题:

  1. 存储过程有输入参数,是的,但是这些特定语句没有参数,它们使用临时表来代替
    这个参数在我的场景中嗅探,还是其他什么?

  2. 显然,它在出现问题时对 MyTable 进行索引扫描,而不是像大多数情况那样在聚集索引 (tID) 上使用查找。为什么可以呢?

  3. 我应该采取哪些进一步措施来调查和解决此问题?我即将启用查询存储并从该 SP 实现对表的日志记录,但还有什么?以及在查询存储中查看什么?

Jon*_*ite 6

#e538 中有多少条记录?引擎将其转换为一系列 OR 子句,我发现在几十个之后,这些子句并不是最优的。根据其他因素,如果您的一个查询在临时表中具有明显更多的条目,则可能会将计划转移到适合该场景的计划,但不适用于另一种场景。

您可以将查询更改为类似这样以获得更一致的性能。

UPDATE M 
SET tMax = 0
FROM MyTable AS M
    INNER JOIN #e538 AS E ON E.b8 = M.tID 
Run Code Online (Sandbox Code Playgroud)

另一种选择(尽管我会看看上面的重写是否可以解决您的问题)是添加一个提示以防止并行性。只需在有问题的陈述后面添加最后一行即可。

UPDATE M 
SET tMax = 0
FROM MyTable AS M
    INNER JOIN #e538 AS E ON E.b8 = M.tID 
OPTION (MAXDOP 1)
Run Code Online (Sandbox Code Playgroud)