为用户定义的表类型参数中的每条记录在存储过程中循环调用存储过程

问题描述 投票:0回答:1

有一个具有复杂业务逻辑的存储过程,其定义为:

CREATE PROCEDURE UspCreatePayment(InvoiceId, UserId, ProcessorId, TransactionAmount)
BEGIN
// Business logic
END

这适用于单个项目处理,但由于对数据库的往返次数,它在处理批次(比如 2000 项)时存在中间件(.Net Core)的性能问题。

我知道理想的解决方案是支持对存储过程的批量处理,但与此同时,我想通过将用户定义的表类型发布到新的存储过程来减少往返次数,方法是将所有项目发布到一个事务中将遍历记录并调用原始存储过程 UspCreatePayment。

这是我的用户定义表类型:

CREATE TYPE typeCreatePayment AS TABLE ( 
            [InvoiceId] [NVARCHAR](36),
            [UserId] [UNIQUEIDENTIFIER], 
            [ProcessorId] [NVARCHAR](32), 
            [TransactionAmount] MONEY
        )

新的存储过程签名:

CREATE PROCEDURE UspCreatePaymentBulk(
                                @typeCreatePayment typeCreatePayment READONLY
        )
AS
  BEGIN
      DECLARE @RowCount BIGINT;
      DECLARE @CurrentRow BIGINT;

      SET @RowCount = (SELECT COUNT(*)
                        FROM @typeCreatePayment )

      WHILE(@CurrentRow <= @RowCount)
        BEGIN
            -- call stored procedure to create payment
            --- How to call EXEC UspCreatePayment here?
            SET @CurrentRow = @CurrentRow + 1
        END
  END

GO 
 
sql sql-server rdbms
1个回答
0
投票

正如您已经注意到的,理想情况下,您首先会使用可以批量处理 TVP 的程序。

但是如果你需要循环,就不要用

WHILE
,它只是一个穷人的光标。而是使用适当的
CURSOR
。你想要一个游标变量,这样它就会自动释放,你想要
FAST_FORWARD

CREATE PROCEDURE UspCreatePaymentBulk
    @typeCreatePayment typeCreatePayment READONLY
AS

SET XACT_ABORT, NOCOUNT ON;

DECLARE
  @InvoiceId NVARCHAR(36),
  @UserId UNIQUEIDENTIFIER,
  @ProcessorId NVARCHAR(32), 
  @TransactionAmount MONEY,
  @crsr CURSOR;

SET @crsr = CURSOR FAST_FORWARD FOR
SELECT
  InvoiceId,
  UserId,
  ProcessorId,
  TransactionAmount
FROM @typeCreatePayment;

OPEN @crsr;

BEGIN TRAN;  -- do you need a transaction?

WHILE 1=1
BEGIN
    FETCH NEXT FROM @crsr INTO
        @InvoiceId,
        @UserId,
        @ProcessorId,
        @TransactionAmount;

    IF @@FETCH_STATUS <> 0
        BREAK;

    EXEC UspCreatePayment
        @InvoiceId = @InvoiceId,
        @UserId = @UserId,
        @ProcessorId = @ProcessorId,
        @TransactionAmount = @TransactionAmount;
END;

COMMIT;

CLOSE @crsr;
© www.soinside.com 2019 - 2024. All rights reserved.