当前位置: 代码网 > it编程>数据库>MsSqlserver > SqlServer SQL语句或存储过程运行慢 使用 WITH RECOMP ILE 或 OPTION (RECOMPILE)(重新编译)

SqlServer SQL语句或存储过程运行慢 使用 WITH RECOMP ILE 或 OPTION (RECOMPILE)(重新编译)

2024年08月01日 MsSqlserver 我要评论
SqlServer SQL语句或存储过程运行慢 使用 WITH RECOMP ILE 或 OPTION (RECOMPILE) SQL Server 尝试根据数据库中的数据和传入的参数确定此查询的最有效执行计划(参数嗅探),然后缓存该计划。这意味着,如果您在数据库中有 10 条记录的情况下创建查询,然后在有 100,000,000 条记录时执行该查询,则缓存的执行计划可能不再是最有效的。当我们看到查询的执行计划时,您会注意到,这次执行计划对行有一个正确的估计,因此查询正在消耗优化特定执行计划所需的资源。

如果您的存储过程包含参数可以重新申明变量把参数接收下,可能解决你过程执行慢的原因。如果未能解决,请参考以下文章内容:

with recompile 子句可以在以下地方使用:

一种是当你创建一个过程时,例如:

create procedure mysp with recompile as
这指示 sql server 在每次调用时重新编译整个过程,并且从不缓存该计划。

另一种情况是当你调用一个过程时:

exec mysp with recompile
这告诉 sql server 重新编译此调用的过程,绕过缓存中的内容。我不知道新计划是否存储在缓存中,或者是否被丢弃。

这两个都是至少从 sql server 4.x 开始就存在于产品中的旧功能。

从sql 2005开始,有一个更好的选择,那就是语句级提示option(recompile):

select ...
from   tbl
where id = @id or @id null
option (recompile)
        这告诉 sql server 每次执行此语句时都重新编译它。这比 with recompile 更强大,原因有二。一是如果这是过程中唯一一个每次都需要重新编译的语句,则通过不重新编译其余部分可以节省资源。但真正强大的是 @id 可以作为常量处理,因此当您有 @id 时可以进行索引查找,而当您没有 @id 时可以进行表扫描。使用 with recompile 无法获得这种效果,因为编译发生在过程启动时,并且 @id 的运行时值未知。

        因此,with recompile 和 create procedure 实际上是一个已停用的功能,您很少(如果有的话)有理由使用它。我认为 exec with recompile 从未被广泛使用过。

选项(重新编译):
首先,让我们创建一个包含关键字option(recompile)的存储过程。

create or alter proc getcustomerorders (@customerid int)
as
select *
from wideworldimporters.sales.orders
where customerid = @customerid
option (recompile)

现在在 sql server management studio (ssms) 中为查询窗口启用执行计划。

接下来,让我们使用两个不同的参数运行以下两个存储过程。

exec getcustomerorders 1060
exec getcustomerorders 90
go

        当我们看到查询的执行计划时,您会注意到,这次执行计划对行有一个正确的估计,因此查询正在消耗优化特定执行计划所需的资源。

        当查询需要更多资源时,它会占用更多资源,当需要更少资源时,它会使用适当的资源。这是一个很大的调整,sql server 每次执行存储过程时都会进行调整。 


参考:sql server - parameter sniffing and option (recompile) - sql authority with pinal dave

queries with option (recompile) and query store - erin stellato

使用 transact-sqlusing transact-sql:

1、连接到数据库引擎。

2、从标准栏中选择“新建查询”。

3、将以下示例复制并粘贴到查询窗口中,然后选择“执行”。此示例创建过程定义。

use adventureworks2022;  
go  
if object_id ( 'dbo.uspproductbyvendor', 'p' ) is not null   
    drop procedure dbo.uspproductbyvendor;  
go  
create procedure dbo.uspproductbyvendor @name varchar(30) = '%'  
with recompile  
as  
    set nocount on;  
    select v.name as 'vendor name', p.name as 'product name'  
    from purchasing.vendor as v   
    join purchasing.productvendor as pv   
      on v.businessentityid = pv.businessentityid   
    join production.product as p   
      on pv.productid = p.productid  
    where v.name like @name;  
    
使用 with recompile 选项重新编译存储过程
选择“新建查询”,然后将以下代码示例复制并粘贴到查询窗口中,然后选择“执行”。这将执行该过程并重新编译该过程的查询计划。

use adventureworks2022;  
go  
execute humanresources.uspproductbyvendor with recompile;  
go

使用 sp_recompile 重新编译存储过程
选择“新建查询”,然后将以下示例复制并粘贴到查询窗口中,然后选择“执行”。这不会执行该过程,但它会标记要重新编译的过程,以便在下次执行该过程时更新其查询计划。

use adventureworks2022;  
go  
exec sp_recompile n'dbo.uspproductbyvendor';   
go 

参考:recompile a stored procedure - sql server | microsoft learn 

option(recompile)总是更快;为什么?

        有时使用option(recompile)是有意义的。根据我的经验,唯一可行的选择是使用动态 sql。在探索这是否适合您的情况之前,我建议您重建统计信息。这可以通过运行以下命令来完成:

exec sp_updatestats
然后重新创建执行计划。这将确保在创建执行计划时将使用最新信息。

option(recompile)每次执行查询时都会重新构建执行计划。我从未听说过这样的描述,但creates a new lookup strategy也许我们只是对同一件事使用了不同的术语。

        创建存储过程时(我怀疑您正在从 .net 调用临时 sql,但如果您使用参数化查询,那么这最终将成为存储过程调用)sql server 尝试根据数据库中的数据和传入的参数确定此查询的最有效执行计划(参数嗅探),然后缓存该计划。这意味着,如果您在数据库中有 10 条记录的情况下创建查询,然后在有 100,000,000 条记录时执行该查询,则缓存的执行计划可能不再是最有效的。

        总结一下 - 我看不出有任何理由option(recompile)会在这里带来好处。我怀疑你只需要更新你的统计数据和执行计划。重建统计数据可能是 dba 工作的一个重要部分,具体取决于你的情况。如果在更新统计数据后仍然遇到问题,我建议发布两个执行计划。

        option (recompile)为什么更快,我想说,每次执行查询时重新编译执行计划的最佳选择是非常不寻常的。

参考:sql - option (recompile) is always faster; why? - stack overflow 

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com