【问题标题】:.NET SQL insert slow compared to JDBC? (JDBC 4x faster).NET SQL 插入速度比 JDBC 慢? (JDBC 快 4 倍)
【发布时间】:2012-07-08 13:07:12
【问题描述】:

我在 C# 中的 .NET Native SQL Client 之间进行了一些测试,并与 java 中的 JDBC 驱动程序进行了比较,结果让我大吃一惊,并认为我一定在 .net 代码中做错了什么。 在一个带有整数和文本字段的表中插入 100 万次的结果,我在每次尝试之前将其清空,运行为发布而构建的程序并由它们自行构建。

  • .NET 100 万行 1 个带有准备好的语句的事务占用了 159 秒。
  • 带有来自微软的 JDBC 驱动程序的 java 100 万行 1 个事务 准备好的报表需要 39 秒。

JDBC 快 4 倍为什么?

我有点惊讶 .NET 这么慢,真的希望我的 .net 代码犯了一个大错误。所以有人知道出了什么问题,或者为什么 .NET 比 jdbc 慢这么多?

.NET 代码:

SqlConnection con = new SqlConnection("Data Source=localhost;Initial Catalog=testameep;User Id=sa;Password=********;");
        con.Open();
        String tempString = "";
        for(int i = 0;i<400;i++)
        {
            tempString += "insert into test1 values (@A" + i.ToString() + ",@B" + i.ToString() + " );";
        }

        SqlCommand com = new SqlCommand(tempString,con);
        for (int i = 0; i < 400; i++)
        {
            com.Parameters.Add("@A" + i.ToString(), SqlDbType.Int);
            com.Parameters.Add("@B" + i.ToString(), SqlDbType.NVarChar,4000);
        }
        com.Transaction = con.BeginTransaction();
        DateTime start = DateTime.Now;
        com.Prepare();
        for(int i=0;i<2500;i++)
        {
            for (int j=0;j<800;j+=2)
            {
                com.Parameters[j].Value = i;
                com.Parameters[j + 1].Value = "test";
            }
            com.ExecuteNonQuery();
        }
        com.Transaction.Commit();
        label1.Text = "Query took:" + (DateTime.Now - start).TotalMilliseconds + " ms";

java代码:

Class.forName( "com.microsoft.sqlserver.jdbc.SQLServerDriver" );
      String dbURL = "jdbc:sqlserver://localhost;databaseName=testameep;user=sa;password=*******";
      Connection dbCon = DriverManager.getConnection( dbURL, "sa" , "*******" );
      dbCon.setAutoCommit( false );

      String tempString = "";
      for(int i = 0;i<400;i++)
      {
          tempString += "insert into test1 values (?,?);";
      }
      System.out.println("Query start");
      long start = System.currentTimeMillis();
      PreparedStatement ps = dbCon.prepareStatement(tempString);
      for(int i=0;i<2500;i++)
      {
          for (int j=1;j<800;j+=2)
          {
              ps.setInt(j, i);
              ps.setString( j+1, "test");
          }
              ps.executeUpdate();
      //    ps.addBatch();
      }
          //This gave the same speed/result as using ps.executeUpdate();
      //ps.executeBatch();
      ps.close();
      dbCon.commit();
      double total = (double)(System.currentTimeMillis() - start) / 1000.0;
      System.out.printf("Query stop: %f seconds\n", total);

更新: SQL 事件探查器结果 .NET:

--Creating the prepared statement .NET
 declare @p1 int
 set @p1=1
 exec sp_prepexec @p1 output,N'@A0 int,@B0 nvarchar(4000),@A1 int,@B1 nvarchar(4000),@A2    int,@B2 nvarchar(4000),@A3 int,@B3 nvarchar(4000),@A4 int,@B4 nvarchar(4000),@A5 int,...(continues)
select @p1

--Inserting rows .NET
exec sp_execute   1,@A0=4,@B0='test',@A1=4,@B1='test',@A2=4,@B2='test',@A3=4,@B3='test',@A4=4,@B4='test',@A5=4,@B5='test',@A6=4,@B6='test',@A7=4,@B7='test',@A8=4,@B8='test',@A9=4,...(continues)
...
2500 rows

SQL 事件探查器结果 JDBC:

--Creating the prepared statment JDBC
declare @p1 int
set @p1=1
exec sp_prepexec @p1 output,N'@P0 int,@P1 nvarchar(4000),@P2 int,@P3 nvarchar(4000),@P4    int,@P5 nvarchar(4000),@P6 int,@P7 nvarchar(4000),@P8 int,@P9 nvarchar(4000),@P10 int,...  (continues)
select @p1

--Inserting rows JDBC
exec sp_execute   1,5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5,N'test',5...(continues)
...
2500 rows

【问题讨论】:

  • 两者都没有使用批量插入,你知道的。就像 .NET 中的 SqlBulkCopy 类一样。
  • 好吧,也许批量插入是错误的称呼。但两者都做相同类型的插入。将从标题中删除大部分内容。我猜你没看过java代码。
  • 不知道为什么它被否决了。我测试了代码并得到了相同的结果。不能真正说出为什么使用 JDBC 应该更快。有任何 Profiler/Tracer 输出要检查吗?
  • 使用分析器结果更新并注意到 .NET 代码插入了 varchar(250) 和 JDBC 一个 nvarchar(4000) 所以我更改了 .NET 代码,但与JDBC @stefan
  • 如果您保存跟踪结果并通过性能调谐器运行它们会怎样?看看它是否与生成的 SQL 代码(变量的处理方式不同)而不是 .NET 开销有关?

标签: java .net sql sql-server-2008 jdbc


【解决方案1】:
        com.ExecuteNonQuery();  
    }  
    com.Transaction.Commit();  

     ps.addBatch(); 
  } 
  ps.executeBatch(); 
  ps.close();   
  dbCon.commit();   

执行方法对我来说似乎不同

【讨论】:

  • 我认为这是正确的。您正在执行 .NET 中循环的每次迭代。
  • 我第一次有 ps.executeUpdate();而不是 ps.addBatch() 和 ps.executeBatch();但两者的表现相同。我现在也在代码中更新和评论了
  • 我不会这样做,而是将 ExecuteNonQuery 移出循环并保留 Java 代码。如果您要创建一个巨大的语句进行测试,那么请确保它被完整地执行一次。也可以尝试在 .NET 中使用 StopWatch 来确定执行时间。
  • @mr-b 还尝试在执行更新运行的循环中的 java 应用程序中放置一个 sleep(5000) 并观察 SQL Profiler。结果是 SQL Profiler 中的每一行之间需要 5 秒,因此它在执行时发送它,就像 .NET 应用程序一样。
  • @mr-moose 我更改为控制台应用程序并使用秒表代替相同的结果。而且我不能将 com.ExecuteNonQuery() 移到循环之外,那么它只会插入 400 行....
猜你喜欢
  • 2012-07-24
  • 2011-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-20
  • 2010-09-26
  • 2012-11-10
  • 1970-01-01
相关资源
最近更新 更多