开发中经常遇到批量插入数据的需求,为了提高开发效率大多会使用ORM架构,个别之处 才会手写SQL,我们使用C#.NET Core5.0开发,所以优先选择了微软的EF。

但是EF原生没有批量操作功能,需要自己扩展或使用第三方的扩展,由于使用第三方扩展怕有风险,因此全部自己手写批量插入和更新。

一段时间后数据多了,这里发现EF查询性能较差,2百万条数据就开始慢得不想用喽,后来换成SqlSugar(下面简称SS),SS的查询确实与原生SQL差不多,很好,很强大,但是它自带的批量插入就不太好用喽,测试后发现性能与官方宣传的差距太大。

本文实测并记录了Oracle 11g r2 单张表113列,批量插入1万条数据的结果:

方法一:

描述 :使用参数数组插入(如果看不懂我的描述,可以继续向下看源代码);

耗时:插入1万条1.729秒

方法二        :

描述 :使用OracleBulkCopy插入;

耗时:插入1万条2.672秒

方法三      :

描述 :使用sugar的Fastest.BulkCopy插入;

耗时:插入1万条4.532秒

以上3个方法多次测试每次耗时略有差异,但基本一致 。

sugar的其他批量插入方法:

经测试只适合插入100条以内的数据,插入数据生成 INSERT ALL  INTO Table() VALUES()语句,个人觉得大量数据不适用,因为数据插入过多后代码会耗尽数据库服务器的cpu,导致无响应的问题

db.Insertable(list).ExecuteCommand();

下面这种就更不行了,是一条一条插入的:

db.Insertable(targetList).UseParameter().ExecuteCommand();

方法一代码:

以下代码根据项目手工编写,经测试性能是最高的,就本文测试的环境下远远高于sqlsugar的性能  。

/// <summary>/// 批量插入;要么全部成功要么全部失败/// </summary>/// <typeparam name="T"></typeparam>/// <param name="list"></param>/// <returns></returns>public static int BulkAdd<T>(List<T> list){Type model = typeof(T);List<PropertyInfo> pi = GetMappedField<T>();//生成数据源与参数OracleParameter[] paras = new OracleParameter[pi.Count];//用于存放数据for (int i = 0; i < pi.Count; i++){PropertyInfo p = pi[i];string name = p.Name;Type pt = p.PropertyType;//bool t1 = pt.IsGenericType;//Console.WriteLine($"序号:{i + 1};字段{ p.Name};类型{ pt.Name };IsGenericType:{pt.IsGenericType}");//if (name == "LLCLY")//{//    string name2 = p.Name;//}//此字段是否可可为空bool IsNullable = pt.Name == "Nullable`1";var colArr = new object[list.Count];for (var rowIndex = 0; rowIndex < list.Count; rowIndex++){object val = p.GetValue(list[rowIndex], null);//时间或整形不能为nullif (IsEnum(p)){//枚举单独处理colArr[rowIndex] = val == null ? DBNull.Value : val.GetHashCode();//Console.WriteLine($"序号:{i + 1};字段{ p.Name};类型{ pt.Name };值{val};hash:{val.GetHashCode()}");continue;}else{if (IsNullable){bool teste1 = pt.DeclaringType != null && pt.DeclaringType.IsEnum;bool teste2 = p.DeclaringType != null && p.DeclaringType.IsEnum;bool teste3 = pt.GetGenericArguments()[0].IsEnum;if (IsEnum(p)){colArr[rowIndex] = (val == null || !IsNullable) ? DBNull.Value : val.GetHashCode();}//Console.WriteLine($"序号:{i + 1};字段{ p.Name};类型{ pt.Name }-{pt.GetGenericArguments()[0].Name};值{val}");}else{colArr[rowIndex] = (val == null && !IsNullable) ? 0 : val;//Console.WriteLine($"序号:{i + 1};字段{ p.Name};类型{ pt.Name };值{val}");}}}//基本类型OracleDbType dt = OracleDbType.Varchar2;if (p.PropertyType.Namespace == "System"){if (IsNullable){//可为空时找真实基本类型pt = pt.GetGenericArguments()[0];}switch (pt.Name){case "String":dt = OracleDbType.Varchar2;break;case "Short":case "Int":case "Int16":dt = OracleDbType.Int16;break;case "Int32":dt = OracleDbType.Int32;break;case "Decimal":dt = OracleDbType.Decimal;break;case "Long":case "Int64":case "Double":dt = OracleDbType.Long;break;case "DateTime":dt = OracleDbType.Date;break;default:break;}}else if (p.PropertyType.IsEnum || pt.BaseType.Name == "Enum" || p.PropertyType.BaseType.Name == "Enum"){//枚举单独处理dt = OracleDbType.Int32;}paras[i] = new OracleParameter($":{name}", dt) { Value = colArr };}//获取表名string tableName = model.Name;TableAttribute[] arrDesc = (TableAttribute[])model.GetCustomAttributes(typeof(TableAttribute), false);if (arrDesc.Length > 0){//EF架构的表属性名tableName = arrDesc.First().Name;}else{//sqlsugar架构的表属性名SugarTable[] tableDesc = (SugarTable[])model.GetCustomAttributes(typeof(SugarTable), false);tableName = tableDesc.First().TableName;}//获取字段string[] propertys = pi.Select(o => o.Name).ToArray();string[] paras_propertys = propertys.Select(o => $":{o}").ToArray();int result = 0;string sql = $"INSERT INTO {tableName}({string.Join(",", propertys)}) VALUES({string.Join(",", paras_propertys)})";using (OracleConnection oracleConnection = new(Conn)){oracleConnection.Open();using (var command = oracleConnection.CreateCommand()){command.ArrayBindCount = list.Count;command.FetchSize = 1000;command.CommandText = sql.ToString();command.CommandType = CommandType.Text;command.Parameters.AddRange(paras);command.BindByName = true;result = command.ExecuteNonQuery();}}return result;}public static bool  IsEnum(PropertyInfo p) {Type pt = p.PropertyType;return pt.IsEnum|| pt.BaseType.Name == "Enum"//标记可为空的枚举  || (pt.GetGenericArguments().Length > 0 && pt.GenericTypeArguments.First().IsEnum);//|| (pt.GetGenericArguments().Length > 0 && pt.GetGenericArguments()[0].IsEnum);}/// <summary>/// 获取映射的字段/// </summary>/// <returns></returns>public static List<PropertyInfo> GetMappedField<T>() {Type model = typeof(T);List<PropertyInfo> proTemp = model.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public).ToList();//过滤出与表对应的字段List<PropertyInfo> pi = new List<PropertyInfo>();for (int i = 0; i < proTemp.Count; i++){PropertyInfo p = proTemp[i];string name = p.Name;Type pt = p.PropertyType;//是否泛型 如:List<User>   Int?  等//bool t1 = pt.IsGenericType;//Console.WriteLine($"序号:{i + 1};字段{ p.Name};类型{ pt.Name };IsGenericType:{pt.IsGenericType}");if (pt.BaseType == null){continue;}//被标记不与数据库映射的字段SugarColumnSugarColumn[] caArray = (SugarColumn[])p.GetCustomAttributes(typeof(SqlSugar.SugarColumn), true);if (caArray.Any(a => a.IsIgnore == true)){continue;}Object[] caArray2 =  p.GetCustomAttributes(typeof(NotMappedAttribute), true);if (caArray2.Length > 0){continue;}//基本类型if (p.PropertyType.Namespace == "System"){pi.Add(p);}else if (p.PropertyType.IsEnum || pt.BaseType.Name == "Enum" || p.PropertyType.BaseType.Name == "Enum"){pi.Add(p);}else{//不与数据库映射的字段continue;}}return pi;}

方法二代码:

 /// <summary>/// 批量插入数据/// [有人说,会自动创建多余的列,还可能多一些数据,且删不掉,但是我没遇到过]/// </summary>/// <param name="table">数据表</param>/// <param name="targetTableName">数据库目标表名</param>/// <returns></returns>public static  bool ExcuteBulkData(DataTable table, string targetTableName=null){bool result = false;using (OracleConnection conn = new(Conn)){conn.Open();using (OracleBulkCopy bulkCopy = new(Conn, OracleBulkCopyOptions.Default)){if (table != null && table.Rows.Count > 0){bulkCopy.DestinationTableName = targetTableName?? table.TableName;bulkCopy.BatchSize = table.Rows.Count;for (int i = 0; i < table.Columns.Count; i++){string col = table.Columns[i].ColumnName;bulkCopy.ColumnMappings.Add(col, col);}bulkCopy.BulkCopyOptions = new() {};bulkCopy.WriteToServer(table);result = true;}}}return result;}

方法三源代码:

引用过sqlsugar后只需要下面一行代码即可实现批量插入,但是性能有限 。

sugar.db.Fastest<CardDel>().BulkCopy(targetList);

总结:

1、方法一适合所有场景 ;方法二可根据情况选择,性能略低于第一种;sqlsugar的批量插入根据情况选择,性能并没有官网宣传的那么高,以上经验全部来源于个人实践后总结,供大家参考 。

2、平时要多自己写实例测试才能得到真实的结果,不能只看官网的宣传。

大数据写入到Oracle数据库(批量插入数据)相关推荐

  1. mysql 批量数据导入报错_Mybatis 批量插入数据 关于Oracle 批量插入报错:ORA

    Mybatis 批量插入数据 关于Oracle 批量插入报错:ORA-00933: SQL 命令未正确结束 问题:用mybaits 批量插入数据到Oracle 数据库的时候, 报错:ORA-00933 ...

  2. mybatis操作Oracle数据库批量插入与更新、运行注意事项、属性含义

    一.项目需求 针对将近300万用户的用电数据进行统计分析,将结果更新保存Oracle数据库.我需要往一个表里面插入数据,数据量总计在500万条左右.一条一条插入的话非常慢,2万条数据近20分钟,后面就 ...

  3. 往Oracel数据库批量插入数据

    往Oracel数据库批量插入数据到目前为止,据我所知,有两种: 第一种,在cmd进入imp命令所在的目录,然后使用imp命令,这种方式批量导入数据速度很快,导入过程会有进程提示,如遇错误,也会告知,如 ...

  4. oracle中如何加字母,Oracle数据库之oracle数据库表插入数据的时候如何产生一个字母+数字...

    本文主要向大家介绍了Oracle数据库之oracle数据库表插入数据的时候如何产生一个字母+数字,通过具体的内容向大家展现,希望对大家学习Oracle数据库有所帮助. Oracle 语句中" ...

  5. Jmeter向数据库批量插入数据

    Jmeter向数据库批量插入数据 下面介绍一下Jmeter向mysql数据库中插入数据的入门操作 1.新建一个线程组,这是必经步骤: 在测试计划上右键–>添加–>Theaders(User ...

  6. c# oracle 事务批量插入数据,[小白求教]c# System.Data.OracleClient 怎么批量插入数据...

    [小白求教]c# System.Data.OracleClient 如何批量插入数据 本帖最后由 qq_16664871 于 2014-10-29 17:00:37 编辑 如题,听说可以用SQL拼接语 ...

  7. ajax向数据库中添加数据,用jqueryajax在数据库中插入数据

    我有一个带有c#(.net4)代码的表单.在这种形式下,用户填写他的规格并提交. 我想在jquery中使用ajax或post方法来预防blink.i写流程代码. "成功"函数执行, ...

  8. EF Core 批量写入数据使用整理_EF Core批量插入数据(一)

    一.EF Core 批量添加数据 问题详解 AddRange() 问题整理: 1.对于批量写入数据,每次几万条情况 使用 Add() 方法不合理 2.使用AddRange() 每次批量写入数据也要有个 ...

  9. oracle+mybatis批量插入数据

    1.Oracle批量操作 我的表结构是 1.1批量插入 1.1.1主键不使用序列 insert into students(sid,sname,ssal,ssex) select 9,'张三',300 ...

最新文章

  1. R语言get函数、get0函数、mget函数获取数据对象实战
  2. yum php56w_yum安装PHP/yum升级PHP
  3. 电脑python下载-Python3.9官方下载
  4. 微软Entity Framework安装和初步研究
  5. 构建javaweb项目
  6. 自己帮别人写的网站可以公开源码吗_雷军靠写代码赚第一个 100 万,马化腾亲自写腾讯网,码农出身的大佬...
  7. react --- 复合组件,传递属性
  8. java form 对象 一对一_java-双向一对一地“对象引用了一个未保存...
  9. 上传 mp4 格式判断_视频如何转换成通用的MP4格式?按下这个键,10秒就能搞定...
  10. 好的产品经理都是这样绘制原型图的...
  11. Visual Studio常用的快捷键
  12. 嵌入式c语言教程 题库 百度云,嵌入式c语言视频教程尚观主讲视频教程
  13. WinRAR5.40版 无广告
  14. org.aspectj aspectjweaver 报错
  15. [Mysql] LEFT函数 | RIGHT函数
  16. 如何准备机器学习工程师的面试 ?
  17. 如何科学增长邮件订阅用户?
  18. 推广那些坑,做好渠道组合拳!
  19. 编号:1001 题目:【2017.1.17】小X的逆袭
  20. python mlagent 安装

热门文章

  1. 如何做一个能赚钱的技术公众号?
  2. iPhone软件开发前需认真考虑问题
  3. 第四章:前缀和、差分(数列)
  4. 大学英语综合教程一 Unit 2 课文内容英译中 中英翻译
  5. Model和ModelMap的区别,以及背后那个男人~
  6. 三万元存一年,利息是多少?银行工作人员:这么存最合算!
  7. Windows系统win10系统流程图软件推荐
  8. TensorFlow简单实例(二):logistic regression
  9. 函数指针数组的一些用法
  10. python遍历文件夹生成标签数据txt文件