当前位置: 首页 > 编程日记 > 正文

大数据高效复制的处理案例分析总结

一个老客户提出这样的需求,希望将SQLServer中的某个表的数据快速复制到SQLite数据库里面以便进行定期的备份处理,数据表的记录大概有50多万条记录,表有100个字段左右,除了希望能够快速做好外,效率是第一位的,他自己测试总是在一两个小时的时间以上。客户提出这样的需求,我我觉得肯定是没有很好的利用事务的特性,否则速度应该会快得多,但是具体能快到什么程度,心里也不太确定。于是按照这个要求,把这样大的表数据复制作为一个案例来进行研究,最终大数据的复制处理,不到20分钟就可以完成全部数据的复制更新处理。本文主要介绍这个需求如何结合实际开发的需要进行处理,达到快速高效的复制数据的目的,并提供相关的实现思路和代码供参考学习。

1、复制数据的需求及开发思路

由于客户是需要做定期的数据备份,因此这样的复制是进行的,因此大数据的复制效率肯定是很重要的,应该尽可能的短时间完成。数据表的记录大概有50多万条记录,表有100个字段左右的需要也是比常规的表数据会多一些,因此需要做好很好的测试,我们根据这样的需求背景,使用一个测试案例来对性能进行测试。

这样多字段的表,数据字段的一一对应,手工肯定是很累的,所以我们使用代码生成工具Database2Sharp来进行快速开发,这样底层的处理我们就可以不用太过关注,而且可以为不同的数据处理,生成不同的数据访问层即可。

在底层我们主要是采用了微软的Enterprise Library的数据库访问模块,因此它能够很好抽象各种数据库的事务,以适应各种不同数据库的事务处理。使用微软的Enterprise Library模块,可以很好支持SQLSever、Oracle、Mysql、Access、SQLite等数据库。

开发框架,常见的分层模式,可以分为UI层、BLL层、DAL层、IDAL层、Entity层、公用类库层等等

框架的基类我们封装了大量的通用性处理函数,包括数据访问层、业务逻辑层的基类,所有的基类函数基本上都带有一个DbTransaction trans = null 的定义,就是我们可以采用事务,也可以默认不采用事务,是一个可选性的事务参数。

如数据访问接口和基于SQLServer的数据访问类的实现图示如下所示。

在最高级的抽象基类AbstractBaseDAL的数据访问层里面,都有大量关于数据操作和相关事务的接口可以使用,因此我们在底层继承的子类,如果我们处理数据的增删改查等操作,基本上就不需要做任何扩展性代码了,这样很符合我们快速开发的目的。

在框架的整个数据访问层,我们都定义了很多公用的、带有事务参数的接口,如果我们在常规的数据处理里面,使用事务的话,那么也是很方便的事情。使用事务的批量处理,对于SQLite的操作来说,效率是非常明显的,具体可以在我之前的随笔里《使用事务操作SQLite数据批量插入,提高数据批量写入速度,源码讲解》可以了解到,他们之间的处理效率是很大差距的。

2、使用代码生成工具生成所需的代码

上面讲到,开发这样的数据复制处理程序,这样多字段的表,数据字段的一一对应,手工肯定是很累的,所以我们使用代码生成工具Database2Sharp来进行快速开发。

因此使用代码生成工具来快速生成所需要的代码,展开数据库后,从数据库节点上,右键选择【代码生成】【Enterprise Library代码生成】就可以生成标准的界面层一下的代码了,由于我们整个案例是非标准的数据复制处理,界面部分不需要利用代码生成工具进行Winform界面的生成的。

生成代码的一步步操作,最后确认一下就可以生成相关的底层代码了

最后我们生成这样的BLL、DAL、IDAL、Entity几个层的项目代码,整个项目的代码各种继承关系已经处理好了,也就具有了基类拥有的增删改查等基础操作了。

我们做两个不同数据库的复制处理操作,关键还是要生成两个不同数据库访问类的代码(也就是生成一个标准的SQLServer后,复制一份代码,修改下继承基类即可实现),如下代码是两个数据访问类的代码,不用增加任何接口即可满足当前项目的需要的了。

最终我们的项目结构如下所示。

3、进行数据复制处理的Winform界面代码逻辑

为了方便整个复制过程的进度展示(很重要),我们设计了进度条以及文字内容,展示处理过程的进度和耗时等信息,最终界面设计如下所示。

整个界面设计利用后台线程的方式对数据复制进行处理,方便及时在界面显示进度而不阻塞界面线程。

具体的界面代码如下所示。

    public partial class FrmMain : Form{private TimeSpan ExecuteTime;private int currentCount = 0;private BackgroundWorker work = new BackgroundWorker();//使用后台线程进行处理,不阻塞界面显示public FrmMain(){InitializeComponent();//定义后台线程的处理work.DoWork += work_DoWork;work.WorkerReportsProgress = true;work.ProgressChanged += work_ProgressChanged;work.RunWorkerCompleted += work_RunWorkerCompleted;}//线程完成后通知结束void work_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e){this.toolStripProgressBar1.Value = 100;this.toolStripProgressBar1.Visible = false;MessageUtil.ShowTips("操作完成");ShowMessage(this.toolStripProgressBar1.Value);//完成
        }/// <summary>/// 在界面显示文本信息/// </summary>/// <param name="percent">完成百分比</param>private void ShowMessage(int percent){if (this.ExecuteTime != null){this.lblTips.Text = string.Format("[当前完成数量:{0},完成百分比:{1}, 执行耗时:{2}毫秒 | {3}分钟{4}秒]",this.currentCount, percent, this.ExecuteTime.TotalMilliseconds, this.ExecuteTime.Minutes, this.ExecuteTime.Seconds);}}/// <summary>/// 报告进度的时候,显示相关的数量、耗时等内容/// </summary>void work_ProgressChanged(object sender, ProgressChangedEventArgs e){this.toolStripProgressBar1.Value = e.ProgressPercentage;this.statusStrip1.Refresh();ShowMessage(e.ProgressPercentage);}/// <summary>/// 后台线程执行的逻辑代码/// </summary>void work_DoWork(object sender, DoWorkEventArgs e){CopyDataUtil util = new CopyDataUtil();//使用一个Action的Lamda表达式,执行通知界面处理util.Start((percent, ts, current) =>{work.ReportProgress(percent);this.ExecuteTime = ts;this.currentCount = current;});}private void btnCopy_Click(object sender, EventArgs e){if(!work.IsBusy){//如果每次要求使用空白数据库测试,那么先删除旧数据库,再复制备份过去即可string dbfile = Path.Combine(Environment.CurrentDirectory, "localdb.db");string bakfile = Path.Combine(Environment.CurrentDirectory, "db.db");if (this.chkCopyEmptyDb.Checked && File.Exists(dbfile)){File.Delete(dbfile);File.Copy(bakfile, dbfile, true);}//显示进度条,并异步执行线程this.toolStripProgressBar1.Visible = true;work.RunWorkerAsync();}}private void FrmMain_FormClosing(object sender, FormClosingEventArgs e){//取消注册的相关事件,防止退出的时候出现异常if(work != null && work.IsBusy){work.ProgressChanged -= work_ProgressChanged; //取消通知事件work.RunWorkerCompleted -= work_RunWorkerCompleted;//取消完成事件
                work.Dispose();}}}

在上面的窗体界面代码里面,最为关键的代码就是具体后台进程的处理逻辑,如下代码所示。

        /// <summary>/// 后台线程执行的逻辑代码/// </summary>void work_DoWork(object sender, DoWorkEventArgs e){CopyDataUtil util = new CopyDataUtil();//使用一个Action的Lamda表达式,执行通知界面处理util.Start((percent, ts, current) =>{work.ReportProgress(percent);this.ExecuteTime = ts;this.currentCount = current;});}

上面的处理逻辑为了方便,把数据的复制内容放到了一个辅助类里面,并在辅助类的Start方法里面传入了界面通知的Action处理函数,这样我们在CopyDataUtil 处理的时候就可以随时进行消息的通知了。

数据复制的Start方法定义如下所示。

        /// <summary>/// 开始执行赋值/// </summary>public void Start(Action<int, TimeSpan, int> doFunc){StartTime = DateTime.Now;//计时开始
InternalCopry(doFunc);//处理数据复制逻辑,并执行外部的函数
EndTime = DateTime.Now;//计时结束}

整个辅助类CopyDataUtil 类里面定义了两个不同数据库类型的对象,方便数据库的赋值处理操作,并且定义了开始时间,结束时间,这样可以统计总共的耗时信息,如下代码所示。

    /// <summary>/// 复制数据的处理类/// </summary>public class CopyDataUtil{//使用一个计时器,对操作记录进行计时private DateTime StartTime, EndTime;//SQLServer数据库表对象private ProductSqlServer sqlserver = null;//SQLite数据表对象private ProductSqlite sqlite = null;public CopyDataUtil(){//构建对象,并指定SQLServer的数据库配置项sqlserver = new ProductSqlServer();sqlserver.DbConfigName = "sqlserver";//构建对象,并指定SQLite的数据库配置项sqlite = new ProductSqlite();sqlite.DbConfigName = "sqlite";}

整个复制数据的逻辑,主要就是基于事务性的处理,按照分页规则,每次按照一定的数量,批量从SQLServer里面取出数据,然后插入SQLite数据库里面,使用事务可以是的SQLite的数据写入非常高效快速,具体代码如下所示。

        /// <summary>/// 大数据复制的处理逻辑/// </summary>/// <param name="doFunc">外部调用的函数</param>private void InternalCopry(Action<int, TimeSpan, int> doFunc){//设置主键,并指定分页数量大小,提高检索效率string primaryKey = "h_id";int pageSize = 1000;PagerInfo info = new PagerInfo(){PageSize = pageSize, CurrenetPageIndex =1};//根据数据的总数,取得总页数int totalPageCount = 1;int totalCount = sqlserver.GetRecordCount();if (totalCount % pageSize == 0){totalPageCount = totalCount / pageSize;}else{totalPageCount = totalCount / pageSize + 1;}totalPageCount = (totalPageCount < 1) ? 1 : totalPageCount;//利用事务进行SQLite数据写入,提高执行响应效率DbTransaction trans = sqlite.CreateTransaction();if (trans != null){//根据每页数量,依次从指定的页数取数据for (int i = 1; i <= totalPageCount; i++){info.CurrenetPageIndex = i;//设定当前的页面,并进行数据获取int j = 1;List<ProductInfo> list = sqlserver.FindWithPager("1=1", info, primaryKey, false);foreach (ProductInfo entity in list){//取得当前数量和进度百分比int current = (i - 1) * pageSize + j;int percent = GetPercent(totalCount, current);//计算程序耗时,执行外部函数进行界面通知TimeSpan ts = DateTime.Now - StartTime;doFunc(percent, ts, current);//执行通知处理//如果不存在主键记录,则写入,否则更新if (!sqlite.IsExistKey(primaryKey, entity.H_id, trans)){sqlite.Insert(entity, trans);}else{sqlite.Update(entity, entity.H_id, trans);}j++;}                    }trans.Commit();}}

至此,整个项目的代码就基本上介绍完毕了,测试整个复制过程,单表50多万的数据,100个字段左右,在开发机器上20分钟不到就复制完成,确实是很不错的成绩了,如果修改为服务器的环境专门做复制处理,肯定速度还会提高不少。

相关文章:

memset函数使用详解

1.void *memset(void *s,int c,size_t n) 总的作用&#xff1a;将已开辟内存空间 s 的首 n 个字节的值设为值 c。 2.例子 &#xff03;include void main(){ char *s"Golden Global View"; clrscr(); memset(s,G,6); printf("%s",s); getchar(); ret…

节后招人平均工资9000上热搜,为什么有些人去哪里都值钱?

我”荒“了。这是很多中国AI企业的现状。《人民日报》报道称&#xff0c;我国AI的人才缺口超过500万&#xff0c;供求比例仅为1&#xff1a;10&#xff01;很多企业已经开始面临“人才荒”的窘境&#xff0c;外媒爆料说&#xff0c;中国企业已经不断在硅谷挖人了&#xff01;目…

关于定于如何弄的漂亮点

</div></div><div class"panel"><h5 οnclickshowhidediv("sidebar_rss");>订阅博客</h5><div class"panel-content" id"sidebar_rss" style"display: block"><ul class"list&…

Happy New Year 2016

大学之前的时间都是按天来过的&#xff0c;期盼着一天一天地快快长大&#xff0c;期盼着过年穿新衣&#xff0c;阖家团聚&#xff0c;其乐融融&#xff1b; 大学的时间都是按周来过的&#xff0c;根据每周的课表周而复始&#xff0c;虽然单调但也是自由自在&#xff0c;简单充实…

HashTable原理与实现

memcached中hashtable部分的源码&#xff0c;hash部分的源码主要分布在assoc.h/c、hash.h/c中&#xff0c;总得来说代码比较简单&#xff0c;这里就稍微介绍一下。hashtable通常包括哈希函数和解决冲突的方法两个最主要的因素&#xff0c;memcached使用的哈希函数为Bob Jenkins…

as3自定义加载图片类

ImageLoader.as类&#xff1a; package{ import flash.display.Bitmap; import flash.display.Loader; import flash.display.Sprite; import flash.events.Event; import flash.events.ProgressEvent; import flash.net.URLRequest; /** * 图片加载类…

想成为一个数据科学家却不知道从何下手?这份路线图带你打开数据科学大门!...

作者 | Jane译者 | 火火酱 责编 | 徐威龙出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;你想成为一名数据科学家吗&#xff1f;你对数据科学了解很多&#xff0c;想知道关于数据科学天花乱坠的宣传都在讲什么吗&#xff1f;那好&#xff0c;你算是来对了地方。在过去…

bzoj 1691: [Usaco2007 Dec]挑剔的美食家

Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 621 Solved: 280[Submit][Status][Discuss]Description 与很多奶牛一样&#xff0c;Farmer John那群养尊处优的奶牛们对食物越来越挑剔&#xff0c;随便拿堆草就能打发她们午饭的日子自然是一去不返了。现在&#xff0c;Farmer…

PHP内核中的哈希表结构

https://github.com/HonestQiao/tipi/commit/17ca680289e490763a6a402f79afa2a13802bb36 下载&#xff1a;https://github.com/HonestQiao/tipi/tree/master/book/sample/chapt03 原文地址&#xff1a;http://www.nowamagic.net/librarys/veda/detail/1344 PHP中使用最为频…

应聘苹果数据科学家,你需要知道些什么?

作者 | Jay Feng译者 | 孙薇&#xff0c;责编 | 屠敏头图 | CSDN 下载自东方 IC出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;以下为译文&#xff1a;苹果公司是全球最大的技术公司之一&#xff0c;从事电子消费产品、计算机软件以及在线服务的设计、开发并销售工…

python 利用模板文件生成配置文件

2019独角兽企业重金招聘Python工程师标准>>> gen.py: __author__ fuhan from jinja2 import Template a{name:a} b{name:b} mode_dict { a:a, b:b } def gen_config(tplt_file, modea): with open(tplt_file, r) as r: tplt Template(r.read()) config mode_dic…

利用Apache的ab命令做Benchmark性能测试

测试系统性能&#xff0c;例如httpsqs # ab -k -c 10 -n 100000 "http://127.0.0.1:1218/?namexoyo&optput&dataabc ab是Apache超文本传输协议(HTTP)的性能测试工具。 其设计意图是描绘当前所安装的Apache的执行性能&#xff0c;主要是显示你安装的Apache每秒可…

MySQL 狠甩 Oracle 稳居 Top1,私有云最受重用,大数据人才匮乏! | 中国大数据应用年度报告...

整理 | 屠敏出品 | CSDN&#xff08;ID:CSDNnews&#xff09;科技长河&#xff0c;顺之者昌&#xff0c;错失者亡。在这个技术百态之中&#xff0c;中国专业的 IT 社区CSDN 创始人&董事长蒋涛曾多次在公开活动中表示&#xff0c;开发者是对技术变革最敏感的人群。这不仅源于…

MAC安装OpenXenManager管理Xenserver

官方文档&#xff1a;https://github.com/OpenXenManager/openxenmanager要求&#xff1a;Python 2.7pyGTK 2.16ConfigObjRavenGTK-VNC&#xff08;仅限Linux&#xff09;Debian / Ubuntu Linux软件包依赖项&#xff1a;python2.7 python-gtk2 glade python-gtk-vnc python-gla…

用Flutter + Dart快速构建一款绝美移动App

作者 | Wojciech Kuroczycki译者 | 弯月来源 | CSDN&#xff08;ID:CSDNnews&#xff09;如今&#xff0c;与前端或移动相关的新框架层出不穷。所有从事Web开发的人都应该熟悉各种目不暇接的新方法以及针对复杂问题的轻量级解决方案。我们不再因为没有现成的技术而烦恼&#xf…

自己写的单链表

link.c #include <stdio.h> #include <malloc.h> #include <string.h> #include <stdlib.h> #include "link.h"/**** 这是一个计算HASH值的算法**/ int time33(char* arKey,int arlength){int h 0;int i;for(i0;i<arlength;i){h h*3…

假装不知道有尽头(博弈论的诡计)

《笑林广记》中记载这样一则笑话。 有一个人去理发铺剃头&#xff0c;剃头匠给他剃得很草率。剃完后&#xff0c;这人却付给剃头匠双倍的钱&#xff0c;什么也没说就走了。一个多月后的一天&#xff0c;这人又来理发铺剃头。剃头匠还记得他上次多付了钱&#xff0c;觉得此人阔绰…

Java Script 第四节课 Java Script的隐式转换

<!DOCTYPE html><html><head><meta charset"utf-8"><title></title><script type"text/javascript">/*if(exp){exp为true的代码段;}else{exp为false的代码段;}*///其它类型转换成布尔类型假的有var a;//undefin…

深入理解malloc和free

1.为什么free是void*&#xff0c;那么它怎么知道要释放多少内存&#xff1f; 《UNIX环境高级编程》 《C语言编程常见问题解答》 《你必须知道的495个C语言问题》 《UNIX环境高级编程》 2.free源码 内存控制块结构定义 struct mem_control_block {int is_available;int si…

根据IP和MAC查端口

进入交换机的命令提示符.输入show ip arp 查出IP地址跟MAC 地址的对照表.再输入show mac-address-table,看一下这个MAC是从哪个端口学到的转载于:https://blog.51cto.com/124130/271033

“数学不好,干啥都不行!”骨灰级程序员:其实你们都是瞎努力!

之前很多程序员读者向我们反馈&#xff1a;1&#xff09;数据结构、编程语句&#xff0c;核心原理都是数学&#xff0c;不会数学搞编程好难&#xff0c;后来发现各种东西还要概率论&#xff0c;还要推收敛&#xff01;近似还要知道泰勒展开&#xff01;2&#xff09;做算法优化…

转:秒杀系统架构分析与实战

原文出处&#xff1a; 陶邦仁 欢迎分享原创到伯乐头条 0 系列目录 秒杀系统架构 秒杀系统架构分析与实战1 秒杀业务分析 正常电子商务流程 &#xff08;1&#xff09;查询商品&#xff1b;&#xff08;2&#xff09;创建订单&#xff1b;&#xff08;3&#xff09;扣减库存&a…

Visual Studio中的《C# 语言规范》

无意中的无意发现了个好东西——《C# 语言规范》&#xff0c;您不用到处下载&#xff0c;它就在您的Visual Studio安装目录中&#xff0c;例如&#xff1a;F:\Program Files\Microsoft Visual Studio 9.0\VC#\Specifications\2052\CSharp Language Specification.doc 这是它的目…

超轻量级中文OCR,支持竖排文字识别、ncnn推理,总模型仅17M

整理 | AI科技大本营光学字符识别&#xff08;OCR&#xff09;技术已经得到了广泛应用。比如发票上用来识别关键字样&#xff0c;搜题App用来识别书本上的试题。近期&#xff0c;这个叫做chineseocr_lite的OCR项目开源了&#xff0c;这是一个超轻量级中文ocr&#xff0c;支持竖…

Redis队列的应用

Redis用双链表list实现队列的 LPUSH key value [value ...] 将一个或多个值 value 插入到列表 key 的表头 如果有多个 value 值&#xff0c;那么各个 value 值按从左到右的顺序依次插入到表头&#xff1a; 比如说&#xff0c;对空列表 mylist 执行命令 LPUSH mylist a b c &…

Python fabric实现远程操作和部署

fabrictitle是开发&#xff0c;但是同时要干开发测试还有运维的活 (o(╯□╰)o)近期接手越来越多的东西&#xff0c;发布和运维的工作相当机械&#xff0c;加上频率还蛮高&#xff0c;导致时间浪费还是优点多。修复bug什么的&#xff0c;测试&#xff0c;提交版本库(2分钟)&…

自己写的哈希表以及解决哈希冲突

哈希表就是键值key-value对&#xff0c;使用hash函数让key产生哈希值&#xff0c;当不同的key产生相同的哈希值时就是哈希冲突了&#xff0c;产生哈希冲突可以使用拉链法。 hash.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include &…

Python与MySQL数据库的交互实战

作者 | Huang supreme编辑 | 郭芮图源 | 视觉中国安装PyMySQL库如果你想要使用python操作MySQL数据库&#xff0c;就必须先要安装pymysql库&#xff0c;这个库的安装很简单&#xff0c;直接使用pip install pymysql&#xff1b;假如这种方式还是安装不上&#xff0c;就用如下链…

Hyper-V的三种网卡

External 虚拟机和物理网络、本地主机都能通信 Internal 虚拟机之间互相通信&#xff0c;并且虚拟机能和本机通信 Private 仅允许运行在这台物理机上的虚拟机之间互相通信

filter-mapping中的dispatcher使用

web.xml里<filter-mapping>中的<dispatcher>作用 2.4版本的servlet规范在部属描述符中新增加了一个<dispatcher>元素&#xff0c;这个元素有四个可能的值&#xff1a;即 REQUEST,FORWARD,INCLUDE和ERROR 可以在一个<filter-mapping>元素中加入任意数目…