【问题标题】:Any SQL Server multiple-recordset stored procedure gotchas?任何 SQL Server 多记录集存储过程的陷阱?
【发布时间】:2009-01-23 12:31:03
【问题描述】:

上下文

我当前的项目是一个大型公共站点(每天 200 万次网页浏览量)站点,该站点混合了 asp classic 和 asp.net 以及 SQL Server 2005 后端。我们重读,偶尔写,几乎没有更新/删除。我们的页面通常涉及单个“主”对象和一堆相关(详细)对象。

我喜欢在单个过程中返回页面所需的所有数据的想法(绝对没有不必要的数据)。诚然,这需要此类页面的专用 proc,但有些页面在我们的整体网站流量中占两位数百分比,因此值得花时间/维护。我们通常只使用 System.Data.SqlClient.SqlDataReader 及其 NextResult 方法从我们的 .net 代码中使用多个记录集。哦,是的,我也没有在这些过程中进行任何更新/插入(表变量除外)。

问题

到目前为止,返回多个记录集的 SQL Server (2005) proc 对我们来说运行良好(在产品中),但我有点担心多记录集 proc 是我最喜欢的新锤子,我正在解决所有问题(钉子)和。有没有我应该知道的多记录集 sql server proc 陷阱?有什么东西会让我希望我没有使用它们吗?特别是关于它影响连接池、内存利用率等的任何事情。

【问题讨论】:

    标签: asp.net sql-server sql-server-2005 performance ado.net


    【解决方案1】:

    以下是多记录集存储过程的一些注意事项:

    它们使重用代码变得更加困难。如果您正在执行多个查询,那么您很有可能能够在另一个页面上重用其中一个查询。

    它们使单元测试变得更加困难。每次您对其中一个查询进行更改时,您都必须测试所有结果。如果发生了变化,您必须深入了解哪个查询未通过单元测试。

    它们使以后调整性能变得更加困难。如果另一个 DBA 在你身后帮助提高性能,他们必须做更多的切片和切块来找出问题的根源。然后,将其与代码重用问题结合起来——如果他们优化了一个查询,那么该查询可能会在几个不同的存储过程中使用,然后他们必须修复所有这些问题——这使得再次进行更多的单元测试。

    它们使错误处理变得更加困难。存储过程中的四个查询可能会成功,而第五个则失败。你必须为此做好计划。

    它们会增加锁定问题并导致 TempDB 中的负载。如果您的存储过程的设计方式需要可重复读取,那么您在存储过程中填充的查询越多,它的运行时间就越长运行,并且将这些结果返回到您的应用服务器所需的时间越长。增加的时间意味着更多的锁争用,并且 SQL Server 必须在 TempDB 中存储更多以进行行版本控制。您提到您的读取量很大,因此这个特定问题对您来说应该不会太糟糕,但您希望在将这个锤子重用于写入密集型应用程序之前了解它。

    【讨论】:

    • 错误处理?我编写的代码中包含多个查询,但我从未发现这对捕获特别繁重。调音?您进行概要分析,找到正在调整的过程中最慢的查询,然后调整它。如果我返回 1 个或 n 个结果集,情况会如何变化?它没有。
    • 关于错误处理 - 如果您使用 MARS,您可能只成功地将 5 个查询中的 4 个返回到您的应用程序。当某些查询成功而某些查询失败时,消费应用程序必须知道如何处理它。这不是 SP 内部的问题,而是每个消耗结果的应用程序中的问题,这就是问题所在。
    • 关于调优 - 如果您在多个 SP 中使用相同的查询,并且在调优期间“修复”了该查询,您不能只在一个地方“修复”它。您必须找出使用该查询的每个地方,并修复它们。最好将结果查询分解为单独的 SP。
    • 一些有趣的观点反对一般使用它们,但并不是没有什么可以阻止我在这个特定实例中使用这些 procs。我在这里故意牺牲了性能的可重用性(听起来你可以阐明性能优势是否值得付出努力)
    【解决方案2】:

    我认为多记录集存储过程在某些情况下很棒,听起来你的可能就是其中之一。

    您的网站获得的流量越大(流量越多),“额外”的性能就越重要。如果您可以将 2-3-4 次调用(可能还有一个新连接)与数据库合二为一,那么您每天可以将数据库点击次数减少 4-6-8 百万,这是相当可观的。

    我很少使用它们,但是当我使用它们时,我从来没有遇到过问题。

    【讨论】:

    • 很高兴知道您在使用多结果集过程时没有遇到任何问题。我也没有(还没有),但是我以前从未在这种负载下使用过它们,所以我想确定一下。
    【解决方案3】:

    我建议在一个存储过程中调用多个存储过程的内部调用,每个内部调用返回 1 个结果集。

    create proc foo 
    as
    execute foobar --returns one result
    
    execute barfoo --returns one result
    
    execute bar  --returns one result
    

    这样,当需求发生变化并且您只需要第 3 和第 5 个结果集时,您可以轻松地调用它们,而无需添加新的存储过程并重新生成数据访问层。如果我想要它们,我当前的应用程序会返回所有参考表(例如美国各州表)。最糟糕的是,当您需要获取一个引用表并且唯一的访问是通过一个存储过程,该存储过程还运行一个昂贵的查询作为它的六个结果集之一。

    【讨论】:

      猜你喜欢
      • 2016-10-31
      • 1970-01-01
      • 2011-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-30
      • 1970-01-01
      相关资源
      最近更新 更多