sql 在运行查询和在存储过程中运行该查询时使用不同的执行计划?

Posted

技术标签:

【中文标题】sql 在运行查询和在存储过程中运行该查询时使用不同的执行计划?【英文标题】:sql using different execution plans when running a query and when running that query inside a stored procedure? 【发布时间】:2012-10-09 13:20:53 【问题描述】:

我有这个问题,

Declare @Prcoces-s-rate float
declare @item varchar(20)
declare @process varchar(20)
declare @branch varchar(20)
set @item = 'shirt'
set @process = 'kt'
set @branch = '1'
select @Prcoces-s-rate =  ProcessPrice from itemwiseproces-s-rate where itemname=@Item and Process=@process and branchid=@branch

当我单手运行时,执行计划只显示3个步骤,你自己看看..

但我有这个procedure sp_newBooking

ALTER PROC sp_newbooking
-- other arguements--
AS
BEGIN

--OTHER FLAGS--

ELSE IF (@Flag = 32)
        BEGIN

            declare @ItemId varchar(max),@ProcessRate float
            --set @BranchId='1'
            select @ProcessCode = DefaultProcessCode from mstconfigsettings where branchid=@BranchId
            select @ItemId= DefaultItemId from mstconfigsettings where branchid=@BranchId
            select @ItemName=  ItemName from itemmaster where itemid=@ItemId and branchid=@BranchId
            select @ProcessRate =  ProcessPrice from itemwiseproces-s-rate where itemname=@ItemName and ProcessCode=@ProcessCode and branchid=@BranchId
            if(@ProcessRate is not null)
            select @ItemName as ItemName,@ProcessCode as ProcessCode,@ProcessRate as ProcessRate
            else
            select @ItemName as ItemName,@ProcessCode as ProcessCode,'0' as ProcessRate
        END

-- OTHER FLAGS --


END

现在!,当我运行它时

exec sp_newbooking
@flag = 32,
@Branchid = 1

执行计划显示 6 个步骤! 这是图片..! 查看查询 4

为什么从过程中执行同一个查询需要6个步骤,而单独执行却需要3个步骤?这是什么鬼?

【问题讨论】:

可能是隐式转换。第二个计划中的计算标量在做什么? (在属性窗口中查看)。存储过程参数的数据类型是否与第一个查询中的变量相同? 我认为@MartinSmith 是正确的。当您在 proc 之外运行查询时,您正在为 @branch 使用值为“1”的 varchar(20) 类型。当您调用 proc 时,您指定 @branchid = 1。在 1 周围看不到引号。 SQL Server 在调用 sp 时将值 1(一个 int)转换为 varchar。我怀疑如果您将您的 SP 称为EXEC sp_newbooking @flag=32, @branchID='1' ,您将获得相同的执行计划。 【参考方案1】:

SQL 可以使用不同的执行计划有很多原因。可能是:

相同查询的不同参数(您在第一个示例中使用常量,第二个示例中的查询可能具有不同的值) 不同的数据(意味着您在开发和生产中运行查询) 参数嗅探 -- 更多内容如下,但首先传递的过程可能具有“所需的”参数 不同的数据类型——正如@MartinSmith 指出的,我们看不到参数声明。您的变量可能与其匹配的字段类型不匹配。

参数嗅探 存储过程执行 'parameter sniffing' 是一种祝福(如果它对您有用),也是一种诅咒(如果它对您不利)。首先通过某人在Zebr% 上搜索zerbrowski。姓氏索引意识到这是非常具体的,并且会从一百万中返回 3 行——因此构建了一个执行计划。为低行结果编译 proc 后,下一个搜索是 S%。嗯,S 是您最常用的名称,匹配 100 万行中的 93,543 行。

那么你能做什么呢? 你可以采取很多步骤来检查这个......

仔细查看变量数据类型,比较您的即席查询、proc 和基础表 (sp_columns mytable)。 隔离运动部件 确保您在同一系统中使用相同数据运行两个查询 运行跟踪以确保 proc 的首次运行使用预期的参数 尝试使用几个不同的参数运行临时查询,看看执行计划如何变化。 如果无法隔离活动,请暂时将WITH RECOMPILE 添加到proc 以比较执行计划。或者,在运行前执行DBCC FREEPROCCACHE。 (免责声明 - 如果这是一个实时系统,请确保您了解这些系统的作用)。

【讨论】:

以上是关于sql 在运行查询和在存储过程中运行该查询时使用不同的执行计划?的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中运行 SQL 查询

SQL 2000 UNION ALL 破坏查询优化

如何在 Oracle 存储过程运行时只提交一个查询

Asp.Net 在运行存储过程时出现超时错误

PL/SQL:将词法参数传递给存储过程

MySQL 存储过程,获取使用游标查询的结果集