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

Potential problems rolling back multiple-line SQL Transaction

我需要使用 Python(BULK INSERT 已关闭)将 CSV 文件插入 SQL 服务器上的 table。我没有使用 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 ... syntaxis。所以我想发送命令

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 服务器批处理大小为64K * 并且默认网络数据包大小为4K,因此默认情况下每个批处理最多可达256MB。 10K 的插入可能会符合该限制,因此您可以尝试将所有内容放在一个批次中发送,并仅在需要时将其分成多个较小的批次。

另一种插入多行的方法是使用来自 table-valued 参数源的 INSERT...SELECT。有关传递 TVP 值的示例,请参见 this answer。我希望使用该技术可以获得更好的性能,因为它避免了解析大批量和 SQL 服务器内部 bulk-inserts TVP 数据到 tempdb。