文章描述:其实我也没想到我会写第二篇关于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语句。