【问题标题】:SQL Transaction with ADO.Net使用 ADO.Net 的 SQL 事务
【发布时间】:2011-02-01 06:28:58
【问题描述】:

我是 C# 数据库交互的新手,我试图在 SqlCommand 和 SqlConnection 对象的帮助下在 SqlTransaction 的帮助下循环写入数据库中的 10000 条记录,并在 5000 之后提交。处理需要 10 秒。

SqlConnection myConnection = new SqlConnection("..Connection String..");
myConnection.Open();
SqlCommand myCommand = new SqlCommand();
myCommand.CommandText = "exec StoredProcedureInsertOneRowInTable Param1, Param2........";
myCommand.Connection = myConnection;
SqlTransaction myTrans = myConnection.Begintransaction();
for(int i=0;i<10000;i++)
{
mycommand.ExecuteNonQuery(); 
if(i%5000==0) 
{
myTrans.commit();  
myTrans = myConnection.BeginTransaction();  
mycommand.Transaction = myTrans;
}
}

上面的代码在数据库中只给了我 1000 行写入/秒。

但是当我尝试在 SQL 中实现相同的逻辑并使用 SqlManagement Studio 在数据库上执行它时,它给了我 10000 写入/秒。 当我比较上述两种方法的行为时,它告诉我在使用 ADO.Net 执行时有大量的逻辑读取。

我的问题是: 1. 为什么ADO.Net执行中有逻辑读? 2. 交易是否有一些握手? 3. 为什么在管理工作室的情况下它们不可用? 4. 如果我想在 DB 上快速插入事务,那么方法是什么? .

关于数据库对象的更新信息

表格: tbl_FastInsertTest 没有主键,只有 5 个字段前三个是 int 类型(F1,F2,F3),后 2 个(F4,F5)是 varchar(30) 类型

存储过程:

create proc stp_FastInsertTest 
{ 
@nF1 int,
 @nF2 int,
 @nF3 int,
 @sF4 varchar(30),
 @sF5 varchar(30) 
 }
 as  
 Begin
 set NoCOUNT on
       Insert into tbl_FastInsertTest
       {
         [F1],
         [F2],
         [F3],
         [F4],
         [F5]
       }
       Values
       {
         @nF1,
         @nF2,
         @nF3,
         @sF4,
         @sF5,
       } end
 --------------------------------------------------------------------------------------

在 SSMS 上执行 SQL 块

--当我在 SSMS 上执行以下代码时,它每秒给我超过 10000 次写入,但是当我尝试在 ADO 上执行相同的 STP 时,它每秒给我 1000 到 1200 次写入

--同时读取无锁

begin trans 
declare @i int 
set @i=0

While(1<>0) 
begin  
 exec stp_FastInsertTest 1,2,3,'vikram','varma'  
 set @i=@i+1 

 if(@i=5000)   
  begin    
   commit trans   
   set @i=0
   begin trans
  end

 end

【问题讨论】:

    标签: c# sql-server ado.net


    【解决方案1】:

    如果你正在运行类似的东西:

    exec StoredProcedureInsertOneRowInTable 'blah', ...
    exec StoredProcedureInsertOneRowInTable 'bloop', ...
    exec StoredProcedureInsertOneRowInTable 'more', ...
    

    在 SSMS 中,这是一个完全不同的场景,所有这些都是一个批次。使用 ADO.NET,您需要为每个 ExecuteNonQuery 支付往返费用 - 实际上我对它管理 1000/s 的速度印象深刻。

    关于逻辑读取,可能只是查看查询计划缓存,但如果不了解更多关于 StoredProcedureInsertOneRowInTable 的信息,则无法评论特定查询是否正在进行中。但我怀疑您在 SSMS 和 ADO.NET 之间有一些不同的SET 条件,这迫使它使用不同的计划 - 这是特别是这样的问题持久化计算的索引列,以及从 sql-xml 字段“提升”的列。

    重新加快速度 - 在这种情况下,table-valued parameters 听起来就是这样,但您还应该查看 other options here

    【讨论】:

    • 非常感谢,感谢大家付出宝贵的时间。抱歉,我没有添加足够的信息,我已经更新了详细信息。
    • 我怎样才能确定我的代码(在问题中给出)正在作为批处理执行,就像第一次看到的那样,它似乎是在 SSMS 本身上执行的。
    • @vikram - 简单地说:不是;您正在向ExecuteNonQuery 拨打 10000 次电话;每一个都是往返的,所以有延迟。它是否相当于通过 SSMS 单独运行每一行 - 即选择第 1 行,执行,选择第 2 行,执行,选择第 3 行,执行...
    【解决方案2】:
    • 对于高性能插入,请查看 SqlBulkCopy 类,如果它适合您,它应该很快。
    • 正如 Sean 所说,使用参数化查询始终是一个好主意。
    • 使用 StringBuilder 类,在单个查询中批处理数千个 INSERT 语句并提交事务是一种经过验证的插入数据的方法:

      var sb=new StringBuilder();

      for(int i=0;i < 1000;i++)
      { 
        sb.AppendFormat("INSERT INTO Table(col1,col2)
      

      VALUES({0},{1});",values1[i],values2[i]); }

      sqlCommand.Text=sb.ToString();
      
    • 您的代码在我看来不正确,您没有在每批中提交事务。您的代码不断打开新交易。

    • 在插入大量数据时删除索引并稍后添加它们始终是一种很好的做法。索引会减慢您的写入速度。
    • Sql Management Studio 没有事务,但 Sql 有,试试这个:
     BEGIN TRANSACTION MyTransaction
        INSERT INTO Table(Col1,Col1) VALUES(Val10,Val20);
        INSERT INTO Table(Col1,Col1) VALUES(Val11,Val21);
        INSERT INTO Table(Col1,Col1) VALUES(Val12,Val23);
        COMMIT TRANSACTION
    

    【讨论】:

    • 非常感谢您宝贵的时间。抱歉,我没有添加足够的信息,我已经更新了详细信息。
    • 我知道我在数据库中插入的方式不是很好,但我的要求是处理大量实时数据(每秒 9000 个)并存储在数据库中。而且我不能进行批量插入,因为我想在收到的数据库中写入它,因为其他一些应用程序可能希望通过“无锁”读取它。 SSMS 也有事务,因为我给出了我在 SSMS 上执行的示例
    【解决方案3】:

    您需要使用参数化查询,以便可以处理和缓存执行路径。由于您使用字符串连接(颤抖,这很糟糕,google sql 注入)来构建查询,SQL Server 将这 10,000 个查询视为单独的单独查询,并为每个查询构建一个执行计划。

    MSDN:http://msdn.microsoft.com/en-us/library/yy6y35y8.aspx 虽然您想要稍微简化他们的代码,并且您必须重置命令中的参数。

    如果您真的非常想快速获取数据库中的数据,请考虑使用 bcp...但您最好先确保数据是干净的(因为没有真正的错误检查/处理。

    【讨论】:

    • 非常感谢您宝贵的时间。抱歉,我没有添加足够的信息,我已经更新了详细信息。
    • Perametarized 查询无疑是不错的选择,但我正在比较 ADO 和 SSMS 的两种情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-11
    • 1970-01-01
    相关资源
    最近更新 更多