代码之家  ›  专栏  ›  技术社区  ›  Sky Sanders

mysql bulkcopy/insert from datareader

  •  2
  • Sky Sanders  · 技术社区  · 14 年前

    我在C_中将一堆行加载到MySQL中。在ms sql中,我可以向sqlbulkcopy提供一个数据读取器,但是mysqlbulkcopy只显示自己作为从文件大容量加载的引导程序。

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

    有没有一种更快的方法可以使用数据读取器源来完成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();
                  }
              }
          }
      }
    
    1 回复  |  直到 14 年前
        1
  •  3
  •   J Jorgenson    14 年前

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

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

    此示例将插入一个由5行组成的“块”。与每行生成的sql相比,可以使用“prepared”语句来提高性能。当您加载了数百万条记录之后,可能只剩下3行要插入。您需要用3行插入重新准备sql。不要试图对缺少的第4和第5条记录使用空值,除非您正在使用“insert ignore”,但这比典型的insert要慢。重新准备是非常快的,值得的结果。

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