一个存储过程中的多个DML语句会导致性能下降吗?

时间:2014-11-12 14:46:15

标签: sql-server performance stored-procedures dml

目前我正在使用MSSQL服务器(2008R2或2012),我想询问在一个程序中放入多个DML语句是否会导致性能下降(丢弃)?

据我所知,这里的经验法则是将每个DML语句放入单独的存储过程中,并从一个包装程序中调用它们。

根据我所说的,使性能变差的事实是,当多个DML在一个过程中时,不能创建和存储该过程的良好执行计划。另一方面,当DML在自己的程序中分开时,每个人都会制定适当的执行计划。

最后值得一提的是,我将把所有DML包装在一个显式事务中 - 无论是在一个程序中还是在单独的程序中。

一个程序中的多个DML语句确实存在很大问题吗?

感谢。

1 个答案:

答案 0 :(得分:3)

你问,因为你所说的不是真的。无论是在单个存储过程中还是在展开过程中,多个DML语句仅在通过显式BEGIN TRAN和COMMIT / ROLLBACK明确分组时才会相互影响。你应该将逻辑放在最有意义的地方(意思是,它最容易理解,最易读,可维护)。

此外,如果单个proc要调用多个proc,那么在单个proc和多个proc中将它们放在概念上真正的区别是什么?当单个proc调用多个proc并且每个都有DML语句时,当将多个DML语句放入单个proc时,这个存储过程的理论属性是否会使事情变得更糟?最后,您仍然只有一个入口点负责多个DML调用。

例如:

INSERT ....

DELETE ....

是两个单独的事务,因为每个查询本身都是一个事务(除非在显式事务中分组)。那么:

BEGIN TRAN

   INSERT ....

   DELETE ....

COMMIT TRAN

是单笔交易。由于并发(即阻塞/死锁),在事务中有多个DML语句会出现性能问题,但如果操作要求两个DML语句在概念上都是一个原子工作单元,那么它们需要在显式交易中组合在一起。

现在,鉴于上面的第一个例子有两个DML语句而没有显式事务,假设它们存在于存储过程中,那就没有什么不同了:

CREATE PROC MasterProc
AS
   EXEC SubProc1;

   EXEC SubProc2;
GO

CREATE PROC SubProc1
AS
   INSERT ...
GO

CREATE PROC SubProc2
AS
   DELETE ...
GO

并且,给出第二个示例,其中两个DML语句在显式事务中分组,假设它们在存储过程中,这与(使用与上述相同的两个SubProc *过程)没有区别:

CREATE PROC MasterProc
AS
   BEGIN TRAN;

      EXEC SubProc1;

      EXEC SubProc2;

   COMMIT TRAN;
GO

修改
一些额外的信息显然是单个存储过程中的多个DML语句对性能更差的原因是(假设)SQL Server无法获得正确的" (即好?)组合的执行计划,但如果DML语句是分开的,那么SQL Server可以生成"适当的" (即好?)每个单独的存储过程的执行计划。

嗯,执行计划确实处于查询级别。当然,在SQL Server 2000之前,只能重新编译整个过程,但从SQL Server 2005开始,可以进行语句级重新编译。但无论哪种方式,每个查询都会自行优化,因此将它们分开并不能提供任何好处。事实上,鉴于局部变量(包括表变量)不能在存储过程中共享,如果必须将每个变量作为输入传递,它肯定会使您在特定存储过程中尝试完成的内容复杂化param并将其中一个或多个传回。该代码很难维护和调试。

编辑2:
以下是一些资源,其中包含有关执行计划缓存和重新编译的信息:

  • Execution Plan Caching and Reuse
    (这是从SQL Server 2008 R2开始;我试图找到更新的东西)
  • DBCC FREEPROCCACHE
    (当前的文档;请注意,从SQL Server 2008开始,可以通过[ ({ plan_handle | sql_handle | pool_name }) ]删除单个计划)
  • Caching Mechanisms
    (这似乎是从SQL Server 2005开始编写的,因为最后一句是"请注意,没有办法强制SQL Server从缓存中删除单个查询计划。"如上所述,从SQL Server 2008开始不再适用。)
  • Recompile a Stored Procedure

请注意,这些文档确实是指在对象(即存储过程等)级别缓存的执行计划。但是,这并不意味着DML语句作为一个整体进行了优化,如果分离出来则会有所不同。将DML语句分离为单独的存储过程的唯一真正好处是,您可以(从SQL Server 2008开始)通过DBCC FREEPROCCACHE ({ plan_handle | sql_handle })单独手动发出重新编译请求。但是,如果这只是偶尔需要的东西,那么重新编译整个存储过程就不会真正受到伤害,与笨重的代码分离相比,这可能不是一个成本。并且,如果它经常需要,那么DML语句本身可以添加OPTION (RECOMPILE),但不会影响该存储过程中的其他查询。

编辑3:(希望最终:) 让我们不要忘记,这仍然是我们正在做的计算机 Science ,而且几乎所有东西都是可测试的。设置一个带有表和几个过程的场景(如上面显示的例子)并运行" master"这应该相当容易。 proc调用子存储过程以及all-in-one proc。您可以查看"实际执行计划"在SSMS中运行它们或从计划缓存中提取计划(如上面的链接资源所示)。所以在技术上,没有人需要依赖这个神秘的人,他建议使用单独的存储过程,甚至是那些认为这个想法最好是过时的,最糟糕的纯粹神话的人; SQL Server会告诉您完全在任何给定情况下它将做什么:)。