第二十一节:ADO层次上的海量数据处理方案(SqlBulkCopy类插入和更新)
一. 简介
1. 背景:
虽然前面EF的扩展插件Z.EntityFramework.Extensions,性能很快,而且也很方便,但是该插件要收费,使用免费版本的话,需要定期更新,如果不更新,将失效,非常麻烦,这个时候SqlBulkCopy类既免费又高效,显得非常合适了。
2. 使用步骤:
①. 引入命名空间:using System.Data.SqlClient;
②. 使用DataTable构造与目标数据库表结构相同的字段,并给其赋值。
③. 使用SqlBulkCopy类,将内存表中的数据一次性插入到目标表中。(看下面的封装可知,可以自行设置插入块的大小)
补充:调用下面的封装这种形式必须内存表中的字段名和数据库表中的字段名一一对应。
二. 使用方式及其性能测试
1. 涉及到的数据库结构:
2. 数据库连接字符串
<add name="CodeFirstModel2" connectionString="data source=localhost;initial catalog=EFDB2;persist security info=True;user id=sa;password=123456;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
3. 代码实践
有两种插入方式,一种是按部就班的每个字段 内存表和数据表进行映射,这个情况无须名称一致,只要映射正确即可。另外一种方式是,直接调用下面的封装方法即可,这种要求内存表中字段和数据库表中的字段名称必须完全一致,一一对应,这样就省去了方法一 中一一匹配映射的繁琐步骤了。
1 public class SqlBulkCopyTest2 {3 public static void TestSqlBulkCopy()4 {5 //一. 构造DataTable结构并且给其赋值6 //1.定义与目标表的结构一致的内存表 排除自增id列 7 DataTable dtSource = new DataTable();8 //列名称如果和目标表设置为一样,则后面可以不用进行字段映射 9 dtSource.Columns.Add("id");
10 dtSource.Columns.Add("t21");
11 dtSource.Columns.Add("t22");
12 //2. 向dt中增加4W条测试数据
13 DataRow dr;
14 for (int i = 0; i <40000; i++)
15 {
16 // 创建与dt结构相同的DataRow对象
17 dr = dtSource.NewRow();
18 dr["id"] = Guid.NewGuid().ToString("N");
19 dr["t21"] = "Name" + i;
20 dr["t22"] = "Address" + i;
21 // 将dr追加到dt中
22 dtSource.Rows.Add(dr);
23 }
24 //二.将内存表dt中的4W条数据一次性插入到t_Data表中的相应列中
25 System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
26 st.Start();
27 string connStr = ConfigurationManager.ConnectionStrings["CodeFirstModel2"].ToString();
28
29 #region 01-按部就班一一对应
30 //{
31 // using (SqlBulkCopy copy = new SqlBulkCopy(connStr))
32 // {
33 // //1 指定数据插入目标表名称
34 // copy.DestinationTableName = "TestTwo";
35
36 // //2 告诉SqlBulkCopy对象 内存表中的 字段和目标表中的字段 对应起来(这里有多个重载,也可以用索引对应)
37 // //前面是内存表,后面是目标表即数据库中的字段
38 // copy.ColumnMappings.Add("id", "id");
39 // copy.ColumnMappings.Add("t21", "t21");
40 // copy.ColumnMappings.Add("t22", "t22");
41
42 // //3 将内存表dt中的数据一次性批量插入到目标表中
43 // copy.WriteToServer(dtSource);
44 // }
45 //}
46
47 #endregion
48
49 #region 02-调用封装
50 {
51 AddByBluckCopy(connStr, dtSource, "TestTwo");
52 }
53 #endregion
54
55 st.Stop();
56 Console.WriteLine("数据插入成功,总耗时为:" + st.ElapsedMilliseconds + "毫秒");
57
58 }
59
60 /// <summary>
61 /// 海量数据插入方法
62 /// (调用该方法需要注意,DataTable中的字段名称必须和数据库中的字段名称一一对应)
64 /// </summary>
65 /// <param name="connectstring">数据连接字符串</param>
66 /// <param name="table">内存表数据</param>
67 /// <param name="tableName">目标数据的名称</param>
68 public static void AddByBluckCopy(string connectstring,DataTable table, string tableName)
69 {
70 if (table != null && table.Rows.Count > 0)
71 {
72 using (SqlBulkCopy bulk = new SqlBulkCopy(connectstring))
73 {
74 bulk.BatchSize = 1000;
75 bulk.BulkCopyTimeout = 100;
76 bulk.DestinationTableName = tableName;
77 bulk.WriteToServer(table);
78 }
79 }
80 }
81 }
4. 性能测试的结论
根据上述的数据测试可以看出来,SqlBulkCopy在处理大数据量插入上速度非常快,甚至比付费的插件Z.EntityFramework.Extensions都要快,所以值得参考和推荐。
既然SqlBulkCopy解决大数据量的插入问题,那么删除和更新怎么办呢? 详见 第二十三节: EF性能篇(三)之基于开源组件 Z.EntityFrameWork.Plus.EF6解决EF性能问题
第二十一节:ADO层次上的海量数据处理方案(SqlBulkCopy类插入和更新)相关推荐
- Python编程基础:第二十一节 函数返回Return
第二十一节 函数返回Return 前言 实践 前言 编程往往是用于实现某种计算并将计算结果进行返回,例如我们定义了一个函数用于计算两个数的和,那么最终的目的是将计算结果返回给用户.所以我们这里要进一步 ...
- 大白话5分钟带你走进人工智能 - 第二十一节 牛顿法和L-BFGS求函数最优解
第二十一节 牛顿法和L-BFGS求函数最优解 这一节中,我们讲解一个新的求函数最优化的方法就是L-BFGS.以下是本节目录. 目录 1-L-BFGS算法简介 2-牛顿法求根 ...
- 上亿海量数据处理方法
上亿海量数据处理方法 1.海量日志数据,提取出某日访问百度次数最多的那个IP. 2.搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下来,每个查询串的长度为1-255字节. 3.有一个1G大 ...
- Scala入门到精通——第二十一节 类型参数(三)-协变与逆变
本节主要内容 协变 逆变 类型通匹符 1. 协变 协变定义形式如:trait List[+T] {} .当类型S是类型A的子类型时,则List[S]也可以认为是List[A}的子类型,即List[S] ...
- 海量数据处理方案——转载总结
转载于:公众号大数据梦想家 https://www.jianshu.com/p/88c6ac4b38c8 https://www.cnblogs.com/myseries/p/10880641.htm ...
- 【java】兴唐第二十一节(LinkedList和泛型)
LinkedList知识点 1.实现了Iterable接口的类具有迭代功能. 2.List接口为Collection的子类,表示线形数据列表,其实现类有:ArrayList(数组线性表)与Linked ...
- 第二十一节(数组概要, 一维、二维数组的声明和使用,数组的排序,数组的查找,)...
一维数组:1:/*数组:1. 数组是一种引用类型2. 数组是一种简单的数据结构,线性的机构3. 数组是一个容器,可以用来存储其他元素,4. 数组也是可以存储任意数据类型的元素5. 数组分为:一维数组, ...
- 小傻蛋的妹妹跟随小甲鱼学习Python的第二十一节021
lambda表达式 冒号前面可以是多个参数: filter过滤器 filter(function or none,iterable) #修改成一行代码实现 list(filter(lambda x:x ...
- 我的《海量数据处理与大数据技术实战》出版啦!
我是如何持续写作的? 其实,关于写作,我也没多想,就是想着总结自己学习和工作中遇到的一些问题.我最开始写文章并不是在CSDN或者其他的一些博客平台,而是在QQ空间.那时的我还在上学,在QQ空间里写下了 ...
最新文章
- Delphi下使用指针的简单总结
- Spring第一讲:初步了解Spring
- Flutter 下拉刷新花式玩法
- 软件测试技术第二次作业——程序错误的判断
- java下拉列表 动态_【示例】教你简单用Java写一个动态更新的下拉列表(无数据库)...
- P1160 队列安排 洛谷
- SIM800C 使用基站定位
- bind9的初步使用(2)
- Hibernate之查询
- mysql数据库存储过程语法错误_奇怪的mysql创建存储过程语法错误
- 等价类划分法写测试用例练习
- 基于氚云平台的应用开发学习(三)
- Matlab 多项式展开或化简(即提取公因式
- 银行金融计算机考试成绩查询系统,速看!人民银行成绩出了!戳进查分数+看排名!...
- 如何定位有故障的显卡,查看序列号,更换
- synergy安装和使用小结
- 英雄会第一届在线编程大赛解题思路
- 为没有历史的互联网留下历史——闪客帝国回忆录
- 鞘氨醇-1-磷酸的生物学作用
- 《学术研究,你的成功之路》阅读笔记
热门文章
- 【STM32】IIC的基本原理(实例:普通IO口模拟IIC时序读取24C02)(转载)
- 2018-2019-2 20165212《网络攻防技术》Exp5 MSF基础应用
- SAS对数据变量的处理
- Redis实现之对象(三)
- Spring实战(十三)Spring事务
- [剑指offer][JAVA]面试题第[14-1、2]题[剪绳子][Leetcode][第343题][整数拆分][数学][动态规划][背包]
- java phantomjs alert_Python+Selenium+PhantomJS脚本中的Javascript警报
- 光谱 波长_【第三课】红外光谱仪及其联用技术
- 3481. 阶乘的和
- redis5 外部不能连接_【硬见小百科】PCB连接的方法