【问题标题】:Calling multiple stored procedures from stored procedure - sql while loop从存储过程调用多个存储过程 - sql while 循环
【发布时间】:2015-09-14 20:13:23
【问题描述】:

我经常听说 while 循环和游标一样糟糕,我不相信这是真的。 从性能的角度来看,是从 C# 调用多个存储过程更好,还是允许一个存储过程解析 XML 数据并以循环方式调用过程?有没有比循环更好的方法在 SQL 中调用未知数量的存储过程?

让我解释一下

我必须设计和实施供应商消息传递系统。有一家第三方公司将 XML 消息发送给来自发件人的收件人。在任何给定时间,我的公司都可能是发件人或收件人。

我想出了一个使用 SQL while 循环来运行存储过程的设计,但我担心它在面对大量循环时可能表现不佳。

基本思路是: 发送者 --> 第三方(消息系统) --> 接收者

当我的公司是接收方时,我的问题可能会发生:

  1. 发件人向第三方公司发送消息
  2. 第三方公司发消息给我公司
  3. WCF 服务收到第三方公司的请求
  4. 调用存储过程,传递接收到的待解析消息的xml
  5. 此存储过程解析 xml 并在 XML 中查找消息
  6. 当循环遍历每条消息并调用存储过程来更新信息时,传递消息实例的 ID。

消息 XML 是这样的:

<envelope>
    <to></to>
    <from></from>
    ...
    <messages>
       <message>
           <id></id>
           ...
           <params>
               <param>
                   <Name></Name>
                   <Value></Value>
               <param>
               ...
           </params>
       </message>
       ...
    </messages>
</envelope>

我可以在每次 XML 传输中接收或发送一条或多条消息。一次可能会收到多条消息。处理发送和接收 XML 的第三方公司的要求是我们始终以成功或失败进行响应。我们有一个 60 秒的超时窗口来响应。由于这些限制,我自然害怕无法在时限内完成我需要做的所有处理,导致超时。

因此,如果我在一次传输中找到消息 1、2 和 3,我将不得不运行存储过程 1、2 和 3。我有一个填充了消息 ID 和存储过程的临时表来运行。

所以While循环基本上是(没有检查这部分的有效性,只是随意的,因为我手边没有SP)

While select count(*) from #temptable > 0
begin
    select top 1 @idMessage = idMessage, @spToRun = spToRun from #temptable
    exec @spToRun @idMessage

    delete from #temptable where idMessage = @idMessage
    select @idMessage = null, @spToRun = null
end

我害怕将它投入生产,然后发现它运行得太慢了。有人给点建议吗?

【问题讨论】:

  • 您的问题是#6。您有一个不基于集合的存储过程。所以你需要重新设计这个过程……或者像你一样做(糟糕的)循环。另一个想法是在 C# 中跨越多个线程/任务,并以这种方式一次发送一个。寻找“c#parallel foreach”.....但请记住,如果您的数据可能重叠,您可能会遇到竞争问题。
  • 出于好奇,有没有办法以基于集合的方式调用 SQL 中的存储过程?
  • 发送xml并粉碎它。

标签: c# xml wcf stored-procedures sql-server-2012


【解决方案1】:

我的建议是继续使用 C# 来解析 xml 并根据需要从 dotnet 端调用 sprocs(只要您保持 sql 简短而甜美)。显然,我并不完全熟悉您的情况,但根据我的经验,很难调试 sql 存储过程,尤其是当它们在逻辑/处理方面很繁重时,就像您正在做的那样,即使您正在使用游标/循环。在像 c# 这样的环境中,控制更加精细,您可以在其中放置断点,在逐步执行处理时观察内存中变量(或在您的情况下为 xml 节点)的值,并捕获更广泛的错误,这在以下情况下非常有用从第三方接收文件。此外,虽然您可能认为 sql 在执行中间件方面与 dot net 一样出色,但它不是中间件,它通常最好在后端为您服务。通常在许多组织中,sql server 将在后端有足够的工作,而且,将来,如果您发现您的 sql server 要求太多,您可能会发现您的 sql server 负担过重,并且它会开始对您产生奇怪的影响。最后,就性能而言,我相信好处超过了额外的行程时间,如果您保持 sql 简单并编译为存储过程,并且如果您将它放在生产服务器上,您应该有足够的内存。至少,如果出于性能原因必须这样做,我会在偏向 C#/dotnet 和依赖 sql server 做尽可能少的处理之间取得平衡。

【讨论】:

  • 谢谢 - 这就是我想要的。与在 SQL 中引发错误相比,我更愿意从 C# 中处理错误和分配任务。我的计划是使用输出参数(XML 或 varchar 类型)并处理来自 C# 的输出,但在思考了更多为什么我打算这样做之后,我意识到我应该只使用 C# 来完成。
【解决方案2】:

最多 1 MB 的 xml,我不会眨眼就在存储过程中粉碎它。 (你没有说你在 xml 中有多少行)。

您将获得比逐行发送更好的性能。

如果您有超过 1 MB,请考虑采用 goldie-locks 方法。不要一个接一个地发送它,不要以“所有东西”发送它,而是有一个外部 c# 进程将 xml 分解成更小的部分。例如:一个有 100,500 行的文件,一次发送 10,000 行,共发送 11 次。

您可以使用金锁方法中的数字。

..

我将在 C# 中验证您的 xml,然后将其作为我所谓的“perfectXml”发送到 sql-server,然后将其切碎,可能会放入 #temp 表中,然后从那里插入。同样,这是关键,从某种意义上说,xml 应该是“完美的”,因为您没有在 tsql 中运行检查以及 if 和 this 或 that 语句。

Row by Row By Agonizing Row 是为鸟儿准备的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-02-10
    • 1970-01-01
    • 1970-01-01
    • 2019-08-01
    • 1970-01-01
    • 2021-09-24
    • 2015-01-19
    相关资源
    最近更新 更多