我有一个只接受2个参数的简单存储过程;第一个总是被提供,第二个总是通过观察为空,并且只是为了不打破来自应用程序的调用。有一个计划的SQL代理任务存储存储过程执行统计信息,然后每周清除缓存的计划。还有夜间预定作业,使用默认参数使用Ola Hallegren的维护程序重建或重组索引。
最近,在清除缓存之后,存储过程执行时间有时会从正常情况下跳到2-15 ms到120,000 ms。在存储过程上调用sp_recompile会将执行时间恢复正常。根据SolarWinds DPA(以前的Ignite),所有等待时间都是CPU /内存。
运行Profiler,我可以复制web应用程序执行的调用,将其粘贴到我的笔记本电脑上运行的SSMS中,并在正常的MS范围内获得执行时间,而根据Profiler的应用程序的持续时间要高得多。距离应用程序需要2分钟的通话将在<在应用程序完成通话后的几秒钟内,我的笔记本电脑就可以使用10毫秒。
我希望两个执行都使用相同的缓存计划并导致相同的性能,但显然不是这种情况,因为我从未见过第二个参数的非null值,所以我不会#39我认为这是一个奇怪的电话,其中包括可能缓解糟糕计划的电话。
以下是整个存储过程代码。其唯一目的是返回一个3行结果集,指示某个特定商城是否包含1到3类型的当前内容。
dbo.usp_s_mall_has_rsc_content
@mall_id INT,
@base_tenant_id INT = NULL
AS
SET NOCOUNT ON;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT 1 AS showcase_item_type_id,
IIF(EXISTS( SELECT *
FROM dbo.content_stream_owner AS cso
JOIN dbo.content_stream_data AS csd ON csd.content_stream_data_id = cso.content_stream_data_id
JOIN dbo.content_stream AS cs ON cs.content_stream_id = csd.content_stream_id
JOIN dbo.content_stream_logins AS csl
ON (csl.mall_id = cso.mall_id OR csl.base_tenant_id = cso.base_tenant_id)
WHERE cso.mall_id = @mall_id
AND (@base_tenant_id IS NULL OR cso.base_tenant_id = @base_tenant_id)
AND csd.content_stream_id = 1
AND csd.end_dt > SYSDATETIME()
AND csd.hidden_flags = 0
AND cs.is_active = 1
AND csl.is_active = 1), 1, 0) AS has_content
UNION
SELECT 2 , IIF(EXISTS( SELECT *
FROM dbo.content_stream_owner AS cso
JOIN dbo.content_stream_data AS csd ON csd.content_stream_data_id = cso.content_stream_data_id
JOIN dbo.content_stream AS cs ON cs.content_stream_id = csd.content_stream_id
JOIN dbo.content_stream_logins AS csl
ON (csl.mall_id = cso.mall_id OR csl.base_tenant_id = cso.base_tenant_id)
WHERE cso.mall_id = @mall_id
AND (@base_tenant_id IS NULL OR cso.base_tenant_id = @base_tenant_id)
AND csd.content_stream_id = 2
AND csd.end_dt > SYSDATETIME()
AND csd.hidden_flags = 0
AND cs.is_active = 1
AND csl.is_active = 1), 1, 0)
UNION
SELECT 3 , IIF(EXISTS( SELECT *
FROM dbo.content_stream_owner AS cso
JOIN dbo.content_stream_data AS csd ON csd.content_stream_data_id = cso.content_stream_data_id
JOIN dbo.content_stream AS cs ON cs.content_stream_id = csd.content_stream_id
JOIN dbo.content_stream_logins AS csl
ON (csl.mall_id = cso.mall_id OR csl.base_tenant_id = cso.base_tenant_id)
WHERE cso.mall_id = @mall_id
AND (@base_tenant_id IS NULL OR cso.base_tenant_id = @base_tenant_id)
AND csd.content_stream_id = 3
AND csd.end_dt > SYSDATETIME()
AND csd.hidden_flags = 0
AND cs.is_active = 1
AND csl.is_active = 1), 1, 0);
答案 0 :(得分:0)
Have you tried making the store procedure recompile everytime?
ALTER PROCEDURE dbo.usp_s_mall_has_rsc_content
@mall_id INT,
@base_tenant_id INT = NULL
WITH RECOMPILE
AS
...
I have seen this problem with some of my stored procedure. You have queries nested inside IIF(...)
. IIF
expects only scalar parameters so somehow SQL Server thinks all the tables involved only give 1 row to the JOIN
and use the inefficient LOOP JOIN
. It blows up as soon as the tables return a few thousand rows each to participate in the join.