【问题标题】:Performance issues calling stored proc from within a stored proc从存储过程中调用存储过程的性能问题
【发布时间】:2010-09-24 16:22:01
【问题描述】:

我从事的项目有以下要求:

TableA 是父表。每当更新 TableA 的任何子记录时,TableA 中的“LastActivityDate”字段都应更新为当前的 UTC 日期。

现在,我知道有很多方法可以做到这一点。我的帖子不是关于这可以实现的许多不同方式。

我最初建议对这个要求使用触发器,但我们的 DBA 拒绝了我,因为他们不希望在这个 DB 中使用触发器(我不知道为什么,这对我的问题并不重要)。我最终创建了一个存储过程,其唯一目的是更新 TableA.LastActivityDate。然后我编写了 TableA 子项的更新/插入存储过程来调用这个存储过程。因此,例如,一个孩子的更新存储过程如下所示:

Create Procedure TableB_UPD
(
 @TableBId INT
 @TableBName VARCHAR(30)
)
AS
BEGIN
 UPDATE dbo.TableB
 SET TableBName = @TableBName
 WHERE
  (TableBId = @TableBId)

 DECLARE @TableAId INT
 SELECT
  @TableAId = TableAId
 FROM
  dbo.TableB
 WHERE
  (TableBId = @TableBId)

 EXEC dbo.TableA_LastActivityDate_UPD @TableAId
END

这是非常直接的代码,我从 TableB_UPD 存储过程中调用 dbo.TableA_LastActivityDate_UPD 存储过程。当我们的 DBA 看到这一点时,他们拒绝在他们的数据库中允许它。他们告诉我,在存储过程中调用存储过程会对性能造成巨大影响。我一直找不到任何好的在线文章来支持这种说法(DBA 也无法给我任何东西)。

我在很多数据库中都看到过这种代码,直到现在还没有听说过任何性能问题。我的问题是:有人可以解释这种代码的性能问题吗?我也非常感谢您对文章的引用。

这是在 SQL Server 2005 中。

【问题讨论】:

  • 恕我直言,我认为您的 DBA 充满了@#$%。 :-)
  • 不允许触发器的 DBA 对性能和执行计划如何实现这一点了解不够,这并不奇怪。
  • 我要指出,无论记录如何更改,触发器都是可以强制执行此要求的唯一可靠方式。一个不明白这一点的 dba 是我不会让我靠近我的数据库的人。要求不是无论何时 GUI 更改数据,而是无论何时更改数据。我会把这个告诉你的老板,让他和 dbas 老板讨论 dba 的无能。
  • 寻找问题解决方案的最佳地点:careers.stackoverflow.com
  • @gerald,但这就是重点,您不能保证 .net 代码是影响数据的唯一途径。

标签: sql sql-server sql-server-2005 stored-procedures


【解决方案1】:

如有疑问,请查看执行计划和 SQL Profiler 以确保您的过程以最佳方式执行。他们可以告诉你比我们更多的情况。

我能想到的唯一问题涉及嵌套存储过程,甚至可能被远程认为是一个问题,是带有事务的嵌套存储过程中的错误处理,但您似乎没有在这里发生这种情况。实际上,我的示例更像是“正确编写存储过程”的案例。

尽管如此,嵌套存储过程对我来说是一个“巨大的性能损失”,但我肯定也找不到任何支持该说法的东西。

【讨论】:

    【解决方案2】:

    我和@mike 在一起,你的代码应该没有任何问题。对我来说,这听起来像是他们曾经听到过或看到过某事,这成为了法律。相反,向他们证明您的代码有效。向他们索要一个测试实例并让它飞起来。

    【讨论】:

    • 我喜欢这个答案,因为它促进了教育、知识共享并且是基于证据的。
    【解决方案3】:

    嵌套存储过程工作正常。在时间敏感的数据仓库情况下,我们几乎经常使用它们。我们有调用 procs 的 procs,一旦我们从客户那里收到数据,这些 procs 会调用 procs 以按月对所有数据进行格式化。

    这样做或直接运行过程或将它们作为查询运行不会降低性能 - 我们对几乎所有过程进行了广泛的效率测试。

    根据您的问题,您可能正在与完全不称职的 DBA 合作。一点知识是一件危险的事情。

    【讨论】:

    • 我不知道我会用勉强能胜任这个词,从描述不胜任似乎更合适。
    【解决方案4】:

    嵌套过程调用的解决方案没有任何问题。但是为了安抚您的 DBA,为什么不在更新表 B 的过程中写出更新语句来更新 LastActivityDate 呢?

    我敢肯定,在这个数据库中,一点点重复的代码将是您遇到的最少的问题

    【讨论】:

      【解决方案5】:

      无论性能如何,我都会以不同的方式在一个事务中进行操作,并且更简单:

      Create Procedure TableB_UPD
      (
       @TableBId INT
       @TableBName VARCHAR(30)
      )
      AS
      BEGIN
       SET XACT_ABORT ON;
       BEGIN TRAN;
       UPDATE dbo.TableB
       SET TableBName = @TableBName
       WHERE
        (TableBId = @TableBId)
      
       UPDATE dbo.TableA
       SET LastActivityDate = CURRENT_TIMESTAMP
       WHERE
        (TableBId = @TableBId)
      
       COMMIT;
      END
      

      【讨论】:

      • 感谢您的回复。在应用程序中,我正在处理事务,分布式事务由 DB 上方的数据层管理。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多