【问题标题】:Potential problems rolling back multiple-line SQL Transaction回滚多行 SQL 事务的潜在问题
【发布时间】:2020-08-13 09:38:58
【问题描述】:

我需要使用 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;
  • @DanGuzman 谢谢!我可以把它全部寄给一批吗?批量大小没有限制?还是您的意思是这个脚本可以分批运行?
  • 我用答案详细说明了我的评论。

标签: python sql-server transactions rollback


【解决方案1】:

这里不需要命名事务。

您可以像这样提交一组事务性的多个语句以有条件地回滚并抛出错误:

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。 10K 插入可能会符合该限制,因此您可以尝试在一个批次中发送所有插入,并仅在需要时将其分成多个较小的批次。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-01
    • 2015-08-27
    • 2011-10-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多