【问题标题】:T-SQL Transaction with many (1000+) INSERTS gets disconnected具有许多 (1000+) INSERTS 的 T-SQL 事务断开连接
【发布时间】:2013-05-01 16:07:38
【问题描述】:

您可以在事务中放入的 INSERT 语句的数量是否有限制? 我收到传输错误,并且在运行语句的过程中连接断开。

我应该只填充一个临时表,然后运行一个 INSERT 语句吗?

在事务中插入 1000 多个中间的错误消息...

Msg 233, Level 20, State 0, Line 0
A transport-level error has occurred when receiving results from the server. 
(provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)

我在 SQL Server 2008 R2 10.50.4000.0 中针对本地 Windows 8 机器(Toshiba Satellite S955、x64 8GB RAM、Intel (R) Core(TM) i5-3317U CPU @ 1.70GHz 1.70 GHz)上的数据库运行脚本)

declare @currentDatabase nvarchar(255);
select @currentDatabase = DB_NAME();

if CHARINDEX('canada', @currentDatabase) = 0
begin
    print 'Please run this script on the Canada server'
    return
end

begin try
begin transaction
SET IDENTITY_INSERT company_name ON
insert into company_name (company_name_id, company_name, display_index, approved_by_administrator, requestor_id, modify_timestamp, active, create_timestamp) values (10000601010001, '6 Day Dental', 5868, 1, NULL, '2013-04-08 00:00:00.000', 1, '2013-04-08 00:00:00.000');
insert into company_name (company_name_id, company_name, display_index, approved_by_administrator, requestor_id, modify_timestamp, active, create_timestamp) values (10000601010002, '7-Eleven', 5869, 1, NULL, '2013-04-08 00:00:00.000', 1, '2013-04-08 00:00:00.000');
insert into company_name (company_name_id, company_name, display_index, approved_by_administrator, requestor_id, modify_timestamp, active, create_timestamp) values (10000601010003, 'AC Properties', 5870, 1, NULL, '2013-04-08 00:00:00.000', 1, '2013-04-08 00:00:00.000');
-- 1287 more INSERT statements...
SET IDENTITY_INSERT company_name OFF

commit
end try
begin catch
    rollback
    declare @Msg nvarchar(max)
    select @Msg=Error_Message();
    raiserror('Error Occured: %s', 20, 101,@Msg) with log
end catch

【问题讨论】:

  • 你是如何执行脚本的?这个错误有already been asked about,但似乎每种情况都没有一个答案。为了回答您关于语句数量的问题,SQL Server 中有一个 maximum batch size,但默认情况下它是 256MB,因此这里似乎不太可能成为问题。
  • 我只是在 SQL Server Management Studio (SQL Server 2008 R2 [10.50.400]) 中针对我的本地数据库运行脚本。

标签: sql-server tsql transactions sql-insert


【解决方案1】:

问题

我相信您的问题在于以下行:

raiserror('Error Occured: %s', 20, 101,@Msg) with log

首先,我们来看看RAISERROR的签名:

RAISERROR ( { msg_id | msg_str | @local_variable }
{ ,严重性 ,state }
[ ,argument [ ,...n ] ] )
[ WITH 选项 [ ,...n ] ]

正如所强调的,我要关注的部分是 severity 论点。在同一个MSDN page 中,您会发现以下内容(关于严重性参数):

[severity] 是与此消息关联的用户定义的严重性级别

还有:

任何用户都可以指定从 0 到 18 的严重级别。从 19 到 25 的严重级别只能由 sysadmin 固定服务器角色的成员或具有 ALTER TRACE 权限的用户指定。对于从 19 到 25 的严重级别,需要 WITH LOG 选项。

到目前为止,一切都很好。从您的代码 sn-p 中,我们可以看到正在通过RAISERROR 生成 严重级别20 的错误消息。因此,使用了WITH LOG 选项。

不过,MSDN page 也注明:

从 20 到 25 的严重级别被认为是致命的。如果遇到严重级别,客户端连接将在收到消息后终止,并将错误记录在错误和应用程序日志中。

因此,实际上,您对RAISERROR 的调用正在终止您的连接。

解决方案

我假设您对 CATCH 块的意图是“重新抛出”导致 CATCH 块运行的原始错误。如果是这样,请查看以下内容(取自Is there an equivalent in T-SQL to C#'s "throw;" to re-throw exceptions?):

...
BEGIN CATCH
    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    SELECT @ErrorMessage = ERROR_MESSAGE(),
           @ErrorSeverity = ERROR_SEVERITY(),
           @ErrorState = ERROR_STATE();

    -- Use RAISERROR inside the CATCH block to return 
    -- error information about the original error that 
    -- caused execution to jump to the CATCH block.
    RAISERROR (@ErrorMessage, -- Message text.
               @ErrorSeverity, -- Severity.
               @ErrorState -- State.
               );
END CATCH;

这使用ERROR_MESSAGE()ERROR_SEVERITY()ERROR_STATE() 来收集有关导致CATCH 块运行的错误的信息。然后它使用RAISERROR 生成带有所述信息的新错误消息。

【讨论】:

    【解决方案2】:

    您确实知道每次插入可以插入一组以上的值。

    values (), (), ()  
    

    有一个最优的。值的总数应小于 1024。
    看起来你有 8 个值,所以每次插入 128 ()。

    【讨论】:

    • 是的,我知道这个选项。我还尝试预填充一个临时表并调用 insert (...) select * from #company_name。
    • 那么我相信这是一个传输错误。尝试不同的交通工具。您可能在命名管道上(为了速度)。如果是这样,请尝试 TCP。并尽量不要登录raiseerror。它可能很简单,错误是违反约束,但错误消息的大小对于传输来说太大了。
    • 我很想知道您从哪里获得这些数字(每个插入/事务最多 1,024 个值?)。你能引用一个来源吗?
    • @stakx Optimal 与 max 不同
    • @Blam:好的,那么“最佳”。我仍然有兴趣了解此建议。您能否引用一个来源,或者这仅仅是来自个人经验?
    【解决方案3】:

    您还可以尝试更基于集合的替代语法。

    INSERT INTO dbo.Employee ( LastName, FirstName ) 
              Select 'Smith', 'John'
    UNION ALL Select 'Jones', 'Mary'
    UNION ALL Select 'Packer', 'Penny'
    UNION ALL Select 'Stokes', 'Daryl'
    

    【讨论】:

      【解决方案4】:

      UNION 看起来像一个语句而不是 1290,因此更好

      (1290 条带有硬编码内容的单独语句真的让我害怕)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-03
        • 1970-01-01
        相关资源
        最近更新 更多