SQL Server 2012存储过程的执行时间差异很大

时间:2015-06-15 14:08:39

标签: caching stored-procedures sql-server-2012

我有一个只接受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);

1 个答案:

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