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

「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 行の「ブロック」を挿入します。行ごとに生成されたSQLよりもパフォーマンスを向上させるために、「準備された」ステートメントを使用できます。これの欠点は、何百万ものレコードをロードした後、挿入する行が 3 行しか残っていない場合があることです。3 行の挿入を使用して SQL を再準備する必要があります。「INSERT IGNORE」を使用していない限り、欠落している 4 番目と 5 番目のレコードに NULL を使用しようとしないでください。ただし、通常の挿入よりも遅くなります。再準備は非常に高速で、結果に値します。

挿入ブロック サイズが 200 行以上のテーブルがあります。挿入あたりの最大行数は、オペレーティング システムが mmap() と malloc() の間のトグル ポイントと見なすメモリのサイズに基づいています。Solaris 10 では、「4096 / rows_size = rows_per_insert」を使用しています。read_buffer_size に大まかに関連する、この問題に関する mysql のバグがどこかにあります。

于 2010-04-06T22:37:06.103 に答える