2010-03-31 139 views
2

我在C#中將一堆行加載到MySql中。在MS Sql中,我可以將DataReader提供給SqlBulkCopy,但MySqlBulkCopy僅將其自身作爲文件批量加載的引導程序。MySql BulkCopy /從DataReader插入

因此,我目前的解決方案是在事務處理循環中使用準備好的命令。

有沒有更快的方式來完成使用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(); 
       } 
      } 
     } 
    } 

回答

3

除了使用「LOAD DATA IN FILE」 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行的「塊」。您可以使用'prepared'語句來提高每行生成的sql性能。對此的負面影響是當你裝載了數百萬條記錄後,你可能只剩下3行插入。您將需要重新準備您的SQL與3行插入。除非使用'INSERT IGNORE',否則不要試圖對缺失的第4和第5條記錄使用NULL,但這比典型插入要慢。重新準備非常快速,值得結果。

我們有一張表,其中插入塊大小爲200+行!每插入的最大行數取決於您的操作系統認爲是mmap()和malloc()之間的切換點的內存大小。對於Solaris 10,我們使用「4096/rows_size = rows_per_insert」。有一個關於這個問題的漏洞,它與read_buffer_size鬆散地相關。

+1

同意,我給了一個鏡頭,並遇到了一個包的大小問題。我通過Command創建了數據庫,並沒有找到用於設置最大數據包大小的DDL語句。因此,利用您的經驗,我需要以某種方式以編程方式確定'mmap()和malloc()'之間的切換點,將我的數據包大小設置爲恰好在下,並相應地準備主插入命令。聽起來對嗎?另一個可能降低功效的問題是源數據有大量的文本字段。 – 2010-04-06 23:19:25