2

我在 C# 中将一堆行加载到 MySql 中。在 MS Sql 中,我可以将 DataReader 提供给 SqlBulkCopy,但 MySqlBulkCopy 仅将自身呈现为从文件批量加载的引导程序。

因此,我当前的解决方案是在事务循环中使用准备好的命令。

有没有更快的方法来使用 DataReader 源完成 MySql 的批量加载?

这是代码。

public override void WriteToServer(IDataReader reader)
  {
      const string insertFormat = "insert into `{3}`.`{0}` ({1}) values ({2});";

      string names = string.Join(",",
                                 _command.Parameters.Cast<MySqlParameter>().Select(p => p.ParameterName).ToArray());
      string vals = string.Join(",",
                                _command.Parameters.Cast<MySqlParameter>().Select(p => "?" + p.ParameterName).
                                    ToArray());

      _command.CommandText = string.Format(insertFormat, _table, names, vals, _schema);

      int reportCounter = 0;
      int totalRecords = 0;
      bool finished = false;

      using (var connection = new MySqlConnection(_source))
      {
          connection.Open();
          _command.Connection = connection;
          _command.Prepare();

          while (!finished)
          {
              using (MySqlTransaction dbTrans = connection.BeginTransaction(IsolationLevel.ReadUncommitted))
              {
                  for (int i = 0; i < BatchSize; i++)
                  {
                      if (!reader.Read())
                      {
                          finished = true;
                          break;
                      }

                      try
                      {
                          for (int p = 0; p < _command.Parameters.Count; p++)
                          {
                              _command.Parameters[p].Value = reader.GetValue(p);
                          }
                          _command.ExecuteNonQuery();
                      }
                      catch (Exception ex)
                      {
                          Trace.WriteLine(ex.Message);
                      }
                      reportCounter++;
                      totalRecords++;

                      if (reportCounter >= NotifyAfter)
                      {
                          reportCounter = 0;
                          OnSqlRowsCopied(new SqlRowsCopiedEventArgs(totalRecords));
                      }
                  }
                  dbTrans.Commit();
              }
          }
      }
  }
4

1 回答 1

3

除了使用“在文件中加载数据”之外,MySQL 还具有非 SQL 标准的“批量插入”机制,您可以在其中指定要插入的多个“值”:http: //dev.mysql.com/doc/refman/5.0/en /插入.html

INSERT INTO TABLE x (a,b,c,e,d,f,g,...)
VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ... )  
     , ( ?, ?, ?, ?, ?, ?, ?, ?, ... )  
     , ( ?, ?, ?, ?, ?, ?, ?, ?, ... )  
     , ( ?, ?, ?, ?, ?, ?, ?, ?, ... )  
     , ( ?, ?, ?, ?, ?, ?, ?, ?, ... )  

此示例将插入 5 行的“块”。您可以使用“准备好的”语句来提高每行生成的 sql 的性能。不利的一面是,当您加载了数百万条记录后,您可能只剩下 3 行要插入。您将需要使用 3 行插入重新准备 SQL。除非您使用“INSERT IGNORE”,否则不要试图对缺失的第 4 条和第 5 条记录使用 NULL,但这比典型的插入要慢。重新准备非常快,值得结果。

我们有一个插入块大小为 200 多行的表!每个插入的最大行数取决于您的操作系统认为是 mmap() 和 malloc() 之间切换点的内存大小。对于 Solaris 10,我们使用“4096 / rows_size = rows_per_insert”。关于这个问题的某个地方有一个 mysql 错误,它与 read_buffer_size 松散相关。

于 2010-04-06T22:37:06.103 回答