回滚多行SQL事务的潜在问题

问题描述

我需要使用Python将CSV文件插入到sql Server上的表中(BULK INSERT关闭)。我不是使用sqlAlchemy,而是编写自己的函数(上帝可以原谅我)。我正在将sql代码列表创建为字符串

sql_code_list = ["insert into table_name values (1,'aa'),(2,'ab'),(3,'ac')...(100,'az')","insert into table_name values (101,'ba'),(102,'bb'),(103,'bc')...(200,'bz')"]

,我计划使用pyodbc软件包一个一个地在数据库中运行它们。为了确保数据完整性,我想使用BEGIN TRANS ... ROLLBACK / COMMIT TRANS ...语法。所以我想发送命令

DECLARE @TransactionName varchar(20) = 'TransInsert'
BEGIN TRANS @TransactionName

然后发送我所有的```INSERT``语句,并发送成功

DECLARE @TransactionName varchar(20) = 'TransInsert'
COMMIT TRANS @TransactionName

或失败

DECLARE @TransactionName varchar(20) = 'TransInsert'
ROLLBACK TRANS @TransactionName

将有许多INSERT语句,比方说10,000条语句,每条语句插入100行,我计划从同一connection.cursor对象中分批发送它们。这整体看起来像是正确的程序吗?从Python应用程序发送这些命令可能会遇到什么问题?

解决方法

这里不需要命名交易。

您可以提交多个这样的事务性批处理,以有条件地回滚并引发错误:

SET XACT_ABORT,NO_COUNT ON;
BEGIN TRY
    BEGIN TRAN;
    <insert-statements-here>;
    COMMIT;
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 ROLLBACK;
    THROW;
END CATCH;

最大SQL Server批处理大小为64K *,默认网络数据包大小为4K,因此默认情况下,每个批处理最大为256MB。 1万次插入可能会在该限制内,因此您可以尝试将所有批量发送一次,然后仅在需要时将其分成多个较小的批次。

另一种插入多行的方法是使用来自表值参数源的INSERT...SELECT。有关传递TVP值的示例,请参见this answer。我希望使用该技术会带来更好的性能,因为它避免了解析大批数据并且SQL Server在内部将TVP数据批量插入tempdb。