我有一个带有几条记录的 DataTable。我想将所有这些记录插入远程数据库。最简单的方法是什么?我读到大多数人遍历 DataTable 的行并逐条插入记录。我只想与远程服务器建立 1 个连接并进行批量插入。可能吗?我正在使用 C# 和 MySQL。
3 回答
尽管 Kemal Taskin 的答案是一个优雅的解决方案,但使用大型 DataTable 的性能却很糟糕。
我尝试插入 37500 条记录,耗时超过 15 分钟。
它似乎一次插入一条记录。
我发现如果我生成一个包含 1000 条记录的 MySQL 插入语句字符串并循环数据直到其完成,我将插入时间减少到 6 秒。这不是批量加载,而是块加载。如果有人能提出更好的解决方案,请告诉我。
public void writeToDBTable(DataTable dt)
{
MySqlConnection conn = new MySqlConnection(globalClass.connString);
conn.Open();
String sql = null;
String sqlStart = "insert into MyTable (run_id, model_id, start_frame,water_year, state_id, obligateCover, DTWoodyCover, perennialGrowth, clonalCover) values ";
Console.WriteLine("Write to DB - Start. Records to insert = {0}", dt.Rows.Count);
int x = 0;
foreach (DataRow row in dt.Rows)
{
x += 1;
if (x == 1)
{
sql = String.Format(@"({0},{1},{2},{3},{4},{5},{6},{7},{8})",
row["runId"],
row["modelId"],
row["startFrame"],
row["waterYear"],
row["currentFrame"],
row["obligateCover"],
row["DTWoodyCover"],
row["perennialGrowth"],
row["clonalCover"]
);
}
else
{
sql = String.Format(sql + @",({0},{1},{2},{3},{4},{5},{6},{7},{8})",
row["runId"],
row["modelId"],
row["startFrame"],
row["waterYear"],
row["currentFrame"],
row["obligateCover"],
row["DTWoodyCover"],
row["perennialGrowth"],
row["clonalCover"]
);
}
if (x == 1000)
{
try
{
sql = sqlStart + sql;
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.ExecuteNonQuery();
Console.WriteLine("Write {0}", x);
x = 0;
}
catch (Exception ex)
{
Console.WriteLine(sql);
Console.WriteLine(ex.ToString());
}
}
}
// get any straglers
if (x > 0)
{
try
{
sql = sqlStart + sql;
MySqlCommand cmd = new MySqlCommand(sql, conn);
cmd.ExecuteNonQuery();
Console.WriteLine("Write {0}", x);
x = 0;
}
catch (Exception ex)
{
Console.WriteLine(sql);
Console.WriteLine(ex.ToString());
}
}
conn.Close();
Console.WriteLine("Write to DB - End.");
}
我不知道这个答案是否为时已晚:)
你可以这样做:
// assume you have a table with one column;
string commandText = "insert into t_test1 (myid) values (@tempid)";
using (MySqlConnection cn = new MySqlConnection(myConnectionString))
{
cn.Open();
using (MySqlCommand cmd = new MySqlCommand(commandText, cn))
{
cmd.UpdatedRowSource = UpdateRowSource.None;
cmd.Parameters.Add("?tempid", MySqlDbType.UInt32).SourceColumn = "tempid";
MySqlDataAdapter da = new MySqlDataAdapter();
da.InsertCommand = cmd;
// assume DataTable dt contains one column with name "tempid"
int records = da.Update(dt);
}
cn.Close();
}
对于 Kemal Taşkın 解决方案,RowState 集必须等于 DataRowState.Added。如果不是这种情况,请执行以下操作:
foreach (DataRow row in dt.Rows)
row.SetAdded();
对于Mr.Black,建议使用sql参数,不要直接使用数据值。
将数据导入 InnoDB 时,请关闭自动提交模式,因为它会为每次插入执行日志刷新到磁盘。要在导入操作期间禁用自动提交,请使用 SET autocommit 和 COMMIT 语句将其括起来:
SET autocommit=0;
... SQL import statements ...
COMMIT;
性能测试:在 2 个表中插入 5400 行
从 CSV 文件插入:3 秒
LOAD DATA INFILE 'data.csv' INTO TABLE myTable 由 '\t' 终止;
使用 Kemal Taşkın 解决方案插入:32 秒
MySqlDataAdapter.Update (DataTable)
逐行插入():41秒
INSERT INTO 表(列)VALUES(值);
INSERT INTO 表(列)VALUES(值);
...
在一个查询中插入所有行:143 秒
INSERT INTO table (columns) VALUES (values), (values), ...;
=> LOAD DATA 是迄今为止性能最高的!
您还可以查看这篇文章: https ://dev.mysql.com/doc/refman/8.0/en/insert-optimization.html