Jos*_*ppo 3 sql-server sp-blitzcache parameter-sniffing
我们有一个多租户数据库。FirmID 是分区键,我们有很多不同的公司。
我遇到了一个参数嗅探问题,我很忙。
我宁愿不在查询中使用任何 [Options]。
我最近的想法是更改我为公司使用的参数的名称。在下面的代码段中,您将看到我将其命名为 @Firm611 而不是使用 @FirmID,其中 611 是 ID 的实际公司。这将为我提供每个公司的唯一查询。
select
c.ID [_cid],
c.Name [Name]
from vwClaims c with(nolock)
where c.FirmID=@Firm611
and (c.Name is not null and c.Name!='')
select
c.ID [_cid],
c.Name [Name]
from vwClaims c with(nolock)
where c.FirmID=@Firm625
and (c.Name is not null and c.Name!='')
Run Code Online (Sandbox Code Playgroud)
运行 Brent Ozar 的 sp_BlitzCache 后,我发现它只是编译为相同的查询并导致重复的缓存条目:
我的问题是我读的结果对吗?即使我更改了参数名称,它真的还在使用相同的计划和参数嗅探吗?
这里有几个不同的问题。
问:如果两个相同的查询使用两个不同的参数名称,SQL Server 会做什么?
SQL Server 将为每个查询构建单独的执行计划。SQL Server 甚至将文本的最轻微更改(即使像空格一样简单)视为不同的查询。
每个变体都将完全独立于另一个被编译和缓存。
问:这两个查询会得到不同的计划还是相同的计划?
SQL Server 将检查参数的内容并基于此构建执行计划。@Firm611的计划会根据@Firm611的选择性编译,@Firm625的计划会根据@Firm625的选择性编译。
如果两个参数碰巧具有相同的选择性,则两个编译的计划可能最终具有完全相同的形状、相同的索引使用、相同的内存授予等。但是,它们仍将独立编译并分别缓存。
问:sp_BlitzCache 中的警告是什么意思?
警告表明您有两个“不同”的查询,它们实际上并没有什么不同 - 它们正在获取形状相同的计划。这意味着您正在浪费时间构建它们的多个版本,因为:
问:选项(重新编译)会解决这个问题吗?
不,因为它们每次运行时都会重新编译,从而导致更高的 CPU 使用率。我只建议在查询每分钟运行一次或更短时间时重新编译提示 - 如果它运行的频率更高,我开始担心 CPU 开销,因为您使用该技巧的所有查询的频繁编译。
我使用每分钟一次的基线,因为这只是这个查询 - 您必须记住服务器上的总工作量。如果您对每个查询都设置重新编译提示,则最终 CPU 利用率可以达到 100% - 即使每个单独的查询每秒仅运行 1 次,当您将每个查询全部考虑在内时,这也是大量编译。
我发现它只是编译为相同的查询并导致重复的缓存条目
我可以理解为什么您会以这种方式读取输出 (DistinctPlanCount),但代码似乎存在错误。所述COUNT
聚集体应引用query_plan_hash
不query_hash
(这是一个常数)。
FROM ( SELECT query_hash,
COUNT(DISTINCT(query_hash)) AS DistinctPlanCount,
COUNT(query_hash) AS PlanCount
FROM sys.dm_exec_query_stats
GROUP BY query_hash
) AS q
Run Code Online (Sandbox Code Playgroud)
应该:
FROM
(
SELECT
qs.query_hash,
COUNT(DISTINCT(qs.query_plan_hash)) AS DistinctPlanCount,
COUNT(qs.query_plan_hash) AS PlanCount
FROM sys.dm_exec_query_stats AS qs
GROUP BY
qs.query_hash
) AS q
Run Code Online (Sandbox Code Playgroud)
您使用的是该程序的旧版本,但该问题在最新版本中仍然存在(尽管已应用其他修复程序)。
即使我更改了参数名称,它真的还在使用相同的计划和参数嗅探吗?
不,您按预期获得每个参数名称的单独计划。每个计划(每个公司)在第一次执行时嗅探自己的参数,并在后续调用中重用该计划,直到由于任何原因发生重新编译。
换句话说,您的计划正在如您所愿。当第一次执行时的 per-firm 参数值没有为同一公司的所有后续执行生成合理的计划时,您仍然可能会遇到问题。这只是普通的参数敏感计划问题,具有通常的解决方法。
正如大卫布朗所说:
这是将所有租户放在同一个数据库中的大问题之一。您应该计划至少隔离“大”和“小”租户。此外,在您的查询中简单地对tenantId 进行硬编码以获取特定于租户的计划是完全合适的。参数用于您需要共享计划时。