文章描述:其实我也没想到我会写第二篇关于Oracle批量写入数据的文章,更没想到的是这两篇时间相距是如此的接近。
其实在写上一篇之前,我是不知道有这个方式的,也算是机缘巧合之下学到了(原谅我的无知),这里稍微介绍下这个方式的优缺点。
首先这里跟之前的方式不太一样,没有进行任何的第三方调用或者利用dll给c#提供的方法进行批量提交,而是运用了Oracle本身的一个批量Sql语句提交。稍微做了一下简单的测试:.
在速度方面的话,尚可,比OracleBulkCopy
和ArrayBindCount
的方式要慢很多,但是肯定要比一条条提交或者使用OracleDataAdapter.Update(DataTable dataTable)
方式快,至于详细的时间效率比较,我没有测试,有兴趣的话可以自己尝试。
同样的,这个方式也有缺点:不能大批量的进行数据提交,否则会超过Oracle Sql的一个长度限制,所以就需要对数据进行分批处理。即处理5万数据的话,可能需要分10批,每次提交5000条(这只是举个例子,实际的数量可能跟数据列、数据值等有一定关系)。但即便如此,这个方式也不失为一个不错的选择。因为一般情况下的数据量也足够了
开发环境:.NET Framework版本:4.5
开发工具: Visual Studio 2019
实现代码:
public class InsertAll {
public static int BulkCopy(DataTable dataTable) {
int result = 0;
List<string> sql_column = new List<string>();
List<string> sql_para = new List<string>();
StringBuilder sqls = new StringBuilder();
List<OracleParameter> paras = new List<OracleParameter>();
foreach(DataColumn column in dataTable.Columns) {
sql_column.Add(column.ColumnName);
}
int index = 0;
foreach(DataRow row in dataTable.Rows) {
sql_para.Clear();
index++;
foreach(DataColumn column in dataTable.Columns) {
string paraName = $"{ column.ColumnName}_{index}";
sql_para.Add(":" + paraName);
OracleParameter para = new OracleParameter(paraName, row[column]);
paras.Add(para);
}
sqls.AppendLine($"into {dataTable.TableName}({string.Join(", ", sql_column)}) values ({string.Join(", ", sql_para)}) ");
}
using(OracleConnection conn = new OracleConnection(ConfigurationManager.ConnectionStrings["default"].ConnectionString)) {
conn.Open();
string sql = "insert all " + sqls.ToString()+ " SELECT 1 FROM DUAL";
OracleCommand cmd = new OracleCommand(sql, conn);
cmd.Parameters.AddRange(paras.ToArray());
result = cmd.ExecuteNonQuery();
conn.Close();
}
return result;
}
}
Stopwatch sw = new Stopwatch();
sw.Start();
int result = InsertAll.BulkCopy(dt);
sw.Stop();
Console.WriteLine("InsertAll time:" + sw.ElapsedMilliseconds + "ms,count:" + result);
代码解析:主要是用到一句很关键的sql语句:insert all into
,然后后面一定要加上SELECT 1 FROM DUAL
语句。