1

我目前正在开发一个遗留应用程序,并继承了一些可疑的 SQL。该项目从未投入生产,但现在正在进行中。在初步测试期间,我发现了一个错误。应用程序调用一个存储过程,该存储过程调用许多其他存储过程、创建游标、循环游标以及许多其他事情。FML。

目前应用程序的设计方式是调用存储过程,然后使用一组新数据重新加载 UI。当然我们要展示的数据还在SQL server端处理,所以展示的时候UI结果是不完整的。为了解决这个问题,我在加载 UI 之前让线程休眠了 30 秒。这是一个可怕的 hack,我想在 SQL 方面正确解决这个问题。

我的问题是......是否值得将分支存储过程转换为函数?这会使主线存储过程在处理之前等待返回值吗?

这是存储过程:

    ALTER PROCEDURE [dbo].[ALLOCATE_BUDGET] 
    @budget_scenario_id uniqueidentifier
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    DECLARE @constraint_type varchar(25)

    -- get project cache id and constraint type
    SELECT @constraint_type = CONSTRAINT_TYPE
    FROM BUDGET_SCENARIO WHERE BUDGET_SCENARIO_ID = @budget_scenario_id

    -- constraint type is Region by Region
    IF (@constraint_type = 'Region by Region')
      EXEC BUDGET_ALLOCATE_SCENARIO_REGIONBYREGION @budget_scenario_id

    -- constraint type is City Wide
    IF (@constraint_type = 'City Wide')
      EXEC BUDGET_ALLOCATE_SCENARIO_CITYWIDE @budget_scenario_id

    -- constraint type is Do Nothing
    IF (@constraint_type = 'Do Nothing')
      EXEC BUDGET_ALLOCATE_SCENARIO_DONOTHING @budget_scenario_id

    -- constraint type is Unconstrained
    IF (@constraint_type = 'Unconstrained')
      EXEC BUDGET_ALLOCATE_SCENARIO_UNCONSTRAINED @budget_scenario_id

    --set budget scenario status to "Allocated", so reporting tabs in the application are populated
    EXEC BUDGET_UPDATE_SCENARIO_STATUS @budget_scenario_id, 'Allocated'
END

为了避免在调用 .NET 应用程序 UI 中显示不完整的结果集,在完成分支调用中的游标之前,是否值得将这些存储过程转换为具有返回值的函数?这会强制 SQL 在完成对 [ALLOCATED_BUDGET] 存储过程的主调用之前等待吗?

  • 存储过程中的最后一个 SQL 语句调用将状态设置为“已分配”。这发生在先前调用中的游标完成处理之前。将这些调用变成函数调用会影响存储过程如何将焦点返回给应用程序吗?

非常感谢任何反馈。我觉得我在使用 SQL 函数方面是正确的,但不是 100% 肯定。

** 附加信息:

  1. 执行代码在连接字符串中使用 [async=true]
  2. 执行代码使用 [SqlCommand].[ExecuteNonQuery] 方法
4

6 回答 6

2

您还可以尝试在子存储过程中使用RETURN 语句,该语句可用于将结果代码返回给父过程。您可以通过类似“ exec @myresultcode = BUDGET_ALLOCATE_SCENARIO_REGIONBYREGION()”的方式调用子过程。我认为这应该迫使父程序等待子程序完成。

于 2009-07-20T17:22:02.263 回答
2

你如何调用程序?我猜你正在使用 ExecuteNonQuery() 来调用该过程。尝试使用 ExecuteScalar() 调用该过程并修改该过程,如下所示:

ALTER PROCEDURE [dbo].[ALLOCATE_BUDGET] 
    @budget_scenario_id uniqueidentifier
AS
BEGIN
   ...

    RETURN True
END

这应该会导致您在 .NET 中的数据执行代码在继续之前等待该过程完成。如果您不希望您的 UI 在过程执行期间“挂起”,请使用 BackgroundWorkerProcess 或类似的东西在单独的线程上运行查询并查找已完成的回调以使用结果更新 UI。

于 2009-07-20T17:24:38.560 回答
2

我从来没有听说过存储过程可以在后台执行的同时返回给调用者。

事实上,我会说我不相信这种情况正在发生。如果您看到 UI 与您认为 SP 应该做的事情之间存在差异,那么我相信它有不同的原因。

连接字符串中是否包含 async=true ?SP 是否正在使用 BeginExecuteReader 或 Begin-anything 执行?

于 2009-07-20T17:35:30.410 回答
0

冒着听起来很简单的风险,我建议您可以创建一个可以存储存储过程状态的表。不知何故,一个标志可以指示整个流程和子流程已完成执行。

您可以从 UI 查询此状态代码,以查看是否已完成。

于 2009-07-20T17:16:43.083 回答
0

将这些调用变成函数调用会影响存储过程如何将焦点返回给应用程序吗?

不。

存储过程不知道它的调用者是一个 UI 应用程序。存储过程中没有任何内容可以影响 UI 应用程序的行为。

UI 应用程序很可能在一个连接上调用存储过程,然后在另一个连接上刷新其数据。有很多方法可以让 UI 延迟刷新,但我要推的是应该有一个单一的数据库连接。

于 2009-07-20T17:24:00.573 回答
0

就个人而言,我更关心替换这些游标而不是将其转换为函数。

而且我不会运行最后一个 proc,直到检查前一个 proc 的有效返回码(如果前面的 proc 之一死了,这件事就很麻烦了!)

还要考虑这是否应该全部在事务中(这些过程是否在更改表中的数据?)

(我是唯一一个觉得有趣的是你有一个 proc 来运行 Do Nothing 的过程吗?)

于 2009-07-20T18:50:54.487 回答