如何将慢参数化插入更改为快速批量复制(即使从内存) [英] How to change slow parametrized inserts into fast bulk copy (even from memory)

查看:148
本文介绍了如何将慢参数化插入更改为快速批量复制(即使从内存)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的代码(.Net 2.0,MS SQL)有这样的

I had someting like this in my code (.Net 2.0, MS SQL)

SqlConnection connection = new SqlConnection(@"Data Source=localhost;Initial
Catalog=DataBase;Integrated Security=True");
  connection.Open();

  SqlCommand cmdInsert = connection.CreateCommand();
  SqlTransaction sqlTran = connection.BeginTransaction();
  cmdInsert.Transaction = sqlTran;

  cmdInsert.CommandText =
     @"INSERT INTO MyDestinationTable" +
      "(Year, Month, Day, Hour,  ...) " +
      "VALUES " +
      "(@Year, @Month, @Day, @Hour, ...) ";

  cmdInsert.Parameters.Add("@Year", SqlDbType.SmallInt);
  cmdInsert.Parameters.Add("@Month", SqlDbType.TinyInt);
  cmdInsert.Parameters.Add("@Day", SqlDbType.TinyInt);
  // more fields here
  cmdInsert.Prepare();

  Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);

  StreamReader reader = new StreamReader(stream);
  char[] delimeter = new char[] {' '};
  String[] records;
  while (!reader.EndOfStream)
  {
    records = reader.ReadLine().Split(delimeter, StringSplitOptions.None);

    cmdInsert.Parameters["@Year"].Value = Int32.Parse(records[0].Substring(0, 4));
    cmdInsert.Parameters["@Month"].Value = Int32.Parse(records[0].Substring(5, 2));
    cmdInsert.Parameters["@Day"].Value = Int32.Parse(records[0].Substring(8, 2));
    // more here complicated stuff here
    cmdInsert.ExecuteNonQuery()
  }
  sqlTran.Commit();
  connection.Close();

使用 cmdInsert.ExecuteNonQuery()注释掉此代码的执行时间少于2秒。使用SQL执行它需要1m 20秒。有大约0.5百万的记录。表已清空。类似功能的SSIS数据流任务大约需要20秒。

With cmdInsert.ExecuteNonQuery() commented out this code executes in less than 2 sec. With SQL execution it takes 1m 20 sec. There are around 0.5 milion records. Table is emptied before. SSIS data flow task of similar functionality takes around 20 sec.


  • 批量插入 )。

  • 我的测试机是Core 2 Duo,配有2 GB RAM。

  • 查看任务管理器时,CPU未完全启用。 IO似乎也没有被充分利用。

  • 模式很简单,就像地狱:一个表以AutoInt为主索引,小于10个int,微小的int和chars(10)。

  • Bulk Insert was not an option (see below). I did some fancy stuff during this import.
  • My test machine is Core 2 Duo with 2 GB RAM.
  • When looking in Task Manager CPU was not fully untilized. IO seemed also not to be fully utilized.
  • Schema is simple like hell: one table with AutoInt as primary index and less than 10 ints, tiny ints and chars(10).

在这里的一些答案后,我发现可以执行从内存批量复制!我拒绝使用批量复制beacuse我认为它必须从文件...

After some answers here I found that it is possible to execute bulk copy from memory! I was refusing to use bulk copy beacuse I thought it has to be done from file...

现在我使用这个,它需要aroud 20秒(像SSIS任务)

Now I use this and it takes aroud 20 sec (like SSIS task)

  DataTable dataTable = new DataTable();

  dataTable.Columns.Add(new DataColumn("ixMyIndex", System.Type.GetType("System.Int32")));   
  dataTable.Columns.Add(new DataColumn("Year", System.Type.GetType("System.Int32")));   
  dataTable.Columns.Add(new DataColumn("Month", System.Type.GetType("System.Int32")));
  dataTable.Columns.Add(new DataColumn("Day", System.Type.GetType("System.Int32")));
 // ... and more to go

  DataRow dataRow;
  object[] objectRow = new object[dataTable.Columns.Count];

  Stream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read);

  StreamReader reader = new StreamReader(stream);
  char[] delimeter = new char[] { ' ' };
  String[] records;
  int recordCount = 0;
  while (!reader.EndOfStream)
  {
    records = reader.ReadLine().Split(delimeter, StringSplitOptions.None);

    dataRow = dataTable.NewRow();
    objectRow[0] = null; 
    objectRow[1] = Int32.Parse(records[0].Substring(0, 4));
    objectRow[2] = Int32.Parse(records[0].Substring(5, 2));
    objectRow[3] = Int32.Parse(records[0].Substring(8, 2));
    // my fancy stuf goes here

    dataRow.ItemArray = objectRow;         
    dataTable.Rows.Add(dataRow);

    recordCount++;
  }

  SqlBulkCopy bulkTask = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, null);
  bulkTask.DestinationTableName = "MyDestinationTable"; 
  bulkTask.BatchSize = dataTable.Rows.Count;
  bulkTask.WriteToServer(dataTable);
  bulkTask.Close();


推荐答案

a href =http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx =nofollow noreferrer> SqlBulkCopy 类批量插入所有记录一次。

Instead of inserting each record individually, Try using the SqlBulkCopy class to bulk insert all the records at once.

创建一个DataTable并将所有记录添加到DataTable,然后使用 SqlBulkCopy WriteToServer 批量插入所有数据。

Create a DataTable and add all your records to the DataTable, and then use SqlBulkCopy.WriteToServer to bulk insert all the data at once.

这篇关于如何将慢参数化插入更改为快速批量复制(即使从内存)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆