有一个具有复杂业务逻辑的存储过程,其定义为:
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
正如您已经注意到的,理想情况下,您首先会使用可以批量处理 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;