【高级内部资料】.NET数据批量写入性能分析 第一篇
【高级内部资料】.NET数据批量写入性能分析 第一篇
说起数据的批量写入,相信大家应该不陌生了,那么我们本系列的文章不准备讲述如何来进行数据的批量写入,而是介绍常用的数据批量写入方法的性能分析。
同时,本篇问题的目的不是告诉大家,何种方式最好(很多人喜欢问“什么是最好的”,在技术中没有所谓的最好的技术,一切都要情况而定),而是给大家一些数据,让大家知道各种不同的情况对性能的影响,从而帮助大家更好地进行抉择。
在.NET环境中,数据批量写入的方式有很多,大家随便上面找一下就可以找到一大堆。在众多的数据批量写入方式中,SqlBulkCopy与SSIS是用的比较多,也是相对而言比较成熟的方案。
也许大家认为SqlBulkCopy我用过,那么,这里就有几个问题大家可以在心里想一想是否可以明确的回答:
- 如何设置SqlBulkCopy的各个属性的,是否确切的直到每一个属性对写入性能的影响,而不是凭感觉。
- 写入的数据量是多少?到底何为批量?1000?100万?还是?
- 不同级别的数据写入对CPU,网络,磁盘的影响?
- 写入的时候,数据库的性能如何?是否被写死了?还是我们以为“数据库会管理好这一切的”
……
还有更多的问题,这里就不在罗列了。那么,我们本系列将会对它们进行深入的对比,如果大家对它们不是很熟悉,可以借此机会学习一下,批量数据的写入操作是每个.NET技术人员都要掌握的技能之一。
SqlBulkCopy是随着.NET Framework 2.0而发布的类,其实SqlBulkCopy就是一个.NET与数据库BULK Insert命令的一个接口。
当我们调用SqlBulkCopy的方法和设置相关的属性的时候,这些都会以BULK Insert命令发送给数据库去执行。SqlBulkCopy有很多的属性,而这些属性的设置可以在不同的程度上面影响数据写入的性能。我们本系列文章不会详细的讲述如何使用SqlBulkCopy类,而是讲述一些我们关心的属性设置(不会把所以的属性设置全部讲完)。
学习本系列文章,因为不是初级的文章,希望大家有一下的技术背景:
- 对.NET知识有比较扎实的理解
- 掌握.NET的并行编程相关的知识
- 如果对SQL Server的内核有一定的认识那就更好了
下面,我们就进入正题。
在把数据从一个地方加载到另外的一个地方的时候,常常会用到Producer/Consumer模式,流程如下(中文理解为:生产与消费模式,这个中文的理解有点怪,以后我们直接就用英文称呼):
- Producer(生产者)从指定的数据源中获取数据(数据源可以是任何的形式,例如文本,XML,数据库,甚至是其他提供数据的服务接口等)
- 如果有需要,Producer对数据进行相关的操作
- Producer将数据传递给Consumer,然后Consumer将数据写入到指定的目标源中。
简单的理解就是:Producer提供数据,Consumer使用数据。
如果大家对SSIS有所了解的话,应该很好理解上面的这种模式。很多的时候,当我们对数据进行传输,转换等操作的时候,SSIS倒是一个非常不多的工具(SSIS在实际中也是非常常用的,可能在国内用的少一点)。当然,除此之外,我们还可以写.NET的代码来进行上述的操作,特别是当数据转换的操作和逻辑特别复杂的时候。
另外,在使用Producer/Consumer模式的时候,我们可以充分的利用多核计算机的能力,使用并行编程来提升性能:使用多个Producer来并行的加载数据,然后将数据传递给多个Consumer,从而使得数据的读取,转换,写入的负载分担在多个核上面。
注意:Producer与Consumer不是一一对应的关系,即不是每个Producer,非得有一个Consumer
用下面的一个图就可以说明这个问题:
对于SqlBulkCopy而言,不是非常适合提到的上面提到的“Producer/Consumer模式” ,因为我们在用SqlBulkCopy将数据写入的时候,直接调用的是WriteToServer方法将数据以一定的形式(DataTable或者DataReader等)写入到了数据库,没有一个明确的Consumer,如果真有,那也是目标数据源了,这个时候Producer就和Consumer是个一一对应的关系了。在这种情况下,如果我们要产生了10个Producer,之后要使用一个Consumer将数据写入(或者少于10的Consumer),那么,我们就需要做更多的事情来克服SqlBulkCopy的限制了。
在我们接下来的性能分析中,我们将会克服上面说的那个限制:我们自己来实现一个继承了IDataReader接口的缓冲对象,这个对象可以用来进行很多的复杂的数据操作,而SqlBulkCopy将会把我们自己实现的缓冲对象当成是DataReader来获取数据。实现如图所示:
采用了上面的实现之后,我们就可以实现这样的方式:
- 使用多个Producer将数据发送给多个Consumer
- 一个Producer将数据发送给多个Consumer
- 多个Producer将数据发送给一个Consumer
同时有一点需要注意的就是:如果数据的Producer和Consumer同时运行,那么会使用很多的内存,并且Producer和Consumer越多,内存使用的越多,因为数据都是在处理的时候都放在内存中的,一直到最后将数据写入到数据库等地方,此时内存就会被释放。
由于时间的限制,我们暂时就唠叨到这里!下一篇,我们就来看看如何进行性能的分析!
系列文章链接:
IIS负载均衡-Application Request Route详解第一篇: ARR介绍
IIS负载均衡-Application Request Route详解第二篇:创建与配置Server Farm
IIS负载均衡-Application Request Route详解第三篇:使用ARR进行Http请求的负载均衡(上)
IIS负载均衡-Application Request Route详解第三篇:使用ARR进行Http请求的负载均衡(下)
IIS负载均衡-Application Request Route详解第四篇:使用ARR实现三层部署架构
查询优化器内核剖析第一篇
查询优化器内核剖析第二篇:产生候选执行计划&执行计划成本估算
查询优化器内核剖析第三篇:查询的执行与计划的缓存 & Hint提示
查询优化器内核剖析第四篇:从一个实例看执行计划
查询优化器内核剖析第七篇:执行引擎之数据访问操作---Scan
查询优化器内核剖析第八篇:执行引擎之数据访问操作---Seek(上)
查询优化器内核剖析第八篇:执行引擎之数据访问操作---Seek(下)