2013-08-02 197 views
1

我插入一个大约900000行的数据表到MySQL DB中,现在13小时后,我的程序已经插入了185000行。这就是慢,我认为^^MYSQL插入很慢

这里是我的代码如何插入我的DataTable到MySQL数据库

//data is typeof DataTable and filled with my data. 

using (System.Data.SqlClient.SqlConnection srcConnection = new SqlConnection(Settings.Default.SourceConnection)) 
using (MySql.Data.MySqlClient.MySqlConnection dstConnection = new MySqlConnection(Settings.Default.TargetConnection)) 
{ 
    if (dstConnection.State != ConnectionState.Open) 
     dstConnection.Open(); 
    if (srcConnection.State != ConnectionState.Open) 
     srcConnection.Open(); 

    var builder = SqlBuilder(tableName, data) 

    foreach (DataRow toCopy in data) 
    { 
     using (var cmdUpdate = builder.GenerateUpdateCommand(dstConnection, toCopy)) 
     { 
      if (cmdUpdate.ExecuteNonQuery() == 0) 
      { 
       using (var cmdInsert = builder.GenerateInsertCommand(dstConnection, toCopy)) 
       { 
        cmdInsert.ExecuteNonQuery; 
       } 
      } 
     } 
    } 
} 

建设者是我自己的类:

public class SqlBuilder 
{ 
    private readonly string _tableName; 
    private readonly DataColumnCollection _columns; 
    private readonly List<string> _columnStrings = new List<string>(); 
    private DataColumn _primaryDataColumn; 
    private readonly Logger _logger = LogManager.GetLogger(typeof(SqlBuilder).FullName); 

    public SqlBuilder(string tableName, DataTable table) 
    { 
     if (tableName == null) throw new ArgumentNullException("tableName"); 
     if (table == null) throw new ArgumentNullException("table"); 
     if (table.PrimaryKey.Count() != 1) throw new ArgumentException("Only one primary key supported", "table"); 

     _tableName = tableName; 
     _columns = table.Columns; 
     _primaryDataColumn = table.PrimaryKey[0]; 

     foreach (DataColumn column in _columns) 
      _columnStrings.Add(column.ColumnName); 
    } 

    public SqlBuilder() 
    { 
    } 

    public string TableName 
    { 
     get { return _tableName; } 
    } 

    public String[] ColumnStrings 
    { 
     get { return _columnStrings.ToArray(); } 
    } 


    public IDbCommand GenerateCountCommand(IDbConnection con) 
    { 
     IDbCommand result = con.CreateCommand(); 
     result.CommandText = String.Format("SELECT COUNT(*) FROM {0}", TableName); 
     return result; 
    } 

    public IDbCommand GenerateDeleteTableCommand(IDbConnection con) 
    { 
     IDbCommand result = con.CreateCommand(); 
     result.CommandText = String.Format("DELETE FROM {0}", TableName); 
     return result; 
    } 

    public IDbCommand GenerateDeleteChangeLogTableCommand(IDbConnection con) 
    { 
     IDbCommand result = con.CreateCommand(); 
     result.CommandText = String.Format("DELETE FROM ChangeLog"); 
     return result; 
    } 

    public String GenerateInsertCommandText() 
    { 
     String result; 

     result = String.Format(
      "INSERT INTO {0} ({1}) VALUES ({2})", 
      TableName, 
      String.Join(",", _columnStrings.ToArray()), 
      String.Join(",", _columnStrings.Select(s => "@" + s).ToArray())); 

     return result; 
    } 

    public string GenerateUpdateCommandText() 
    { 
     String result; 

     result = String.Format(
      "UPDATE {0} SET {1} WHERE {2}", 
      TableName, 
      String.Join(", ", _columnStrings.Where((s =>!_primaryDataColumn.ColumnName.Equals(s))).Select(s => s+"[email protected]" + s).ToArray()), 
      _primaryDataColumn.ColumnName+"[email protected]"+_primaryDataColumn.ColumnName 
      ); 

     return result; 
    } 

    public string GenerateDeleteCommandText(int id) 
    { 
     string result = String.Format("DELETE FROM {0} WHERE {1} = {2}", _tableName , _columnStrings[0], id); 
     return result; 
    } 

    public IDbCommand GenerateInsertCommand(IDbConnection con, DataRow row) 
    { 
     IDbCommand result = con.CreateCommand(); 
     result.CommandText = GenerateInsertCommandText(); 

     result = FillParameters(row, result); 

     if (_logger.IsTraceEnabled) _logger.Trace(result.CommandText); 

     return result; 
    } 

    public IDbCommand GenerateUpdateCommand(IDbConnection connection, DataRow dataRow) 
    { 
     IDbCommand result = connection.CreateCommand(); 
     result.CommandText = GenerateUpdateCommandText(); 

     result = FillParameters(dataRow, result); 

     if (_logger.IsTraceEnabled) _logger.Trace(result.CommandText); 

     return result; 
    } 

    public IDbCommand GenerateDeleteCommand(IDbConnection con, int id) 
    { 
     IDbCommand result = con.CreateCommand(); 

     result.CommandText = GenerateDeleteCommandText(id); 

     return result; 
    } 

    private IDbCommand FillParameters(DataRow row, IDbCommand result) 
    { 
     foreach (var curColumn in _columnStrings) 
     { 
      IDbDataParameter parameter = result.CreateParameter(); 
      parameter.ParameterName = curColumn; 
      parameter.Value = row[curColumn]; 
      result.Parameters.Add(parameter); 
     } 

     return result; 
    } 
} 

任何人任何想法如何使这更快???

+0

您应该使用分析器来查找“热线”。我使用附带高级和最终版本的Visual Studio分析器。 –

+0

似乎你需要一个批量插入,请参阅相关问题:http://stackoverflow.com/questions/11189983/how-do-i-create-a-safe-query-for-performing-a-bulk-insert-in -mysql - 使用 - mysqlco。希望这可以帮助 –

回答

1

插入几行的一个语句,像这样:

INSERT INTO table (...) VALUES 
(values for first record), 
(values for second record), 
... 

你也许可以插入一个几十行的一个声明中这样,根据记录大小。

0

我在参数类似的建设过程中已经发现,设置参数的“SourceColumn” ......在你的“FillParameters”方法尝试添加

parameter.SourceColumn = curColumn;

然后,你的INSERT程序中,而不是

foreach(DataRow) 
    Build The Insert Command 
     Execute Insert 

变化

Build The Insert Command 
    ForEach(DataRow) 
     Execute Insert 

这样,您就不必保持遍地建设命令。该参数将转到正在处理的数据行的源列并为您拉入。

当我编写我的版本时,同样适用于更新和删除。我有先前构建的命令和参数,并在我正在使用的DataTable期间保留它们。

因此,您可以在foreach(DataRow)之前实际构建insert和update命令,然后使用它们。一遍又一遍。很明显,只要测试上传几条记录,以确认它在你认为它会全部通过之前与其他方式协同工作。