想必每个DBA都喜欢挑战数据导入时间。时间越短,工作效率越高,能充分证明他的实力。在实际工作中,有时需要将大量数据导入数据库,然后用于各种程序计算。
本文将推荐一个实验案例,挑战4秒钟的限制,并允许数百万数据立即导入sql server。
本实验将使用5中的方法来完成这一过程,并详细记录每种方法所花费的时间。使用的工具有visual studio 2008和sql server 2000,sql server 2008,
100万条数据分别通过方法5导入到SQL Server 2000和SQL Server 2008中。实验环境是具有2.0GCPU和2G内存的DELL 2850双服务器。
感兴趣的朋友可以下载源代码,自己验证时间。
好了,我们分别使用基本的Insert语句,BULK INSERT语句,多线程中的BULK INSERT,多线程中的SqlBulkCopy类和SqlBulkCopy类。
挑战4秒的极限。还有一点需要说明。在这个实验中,IsLine框架中的DataProvider模块用于执行SQL语句。这个模块只读取和封装SQL配置。
它不会对最终结果产生本质的影响。关于IsLine框架的框架知识,请参考“IsLine框架”系列文章。
数据库使用SQL Server 2000和SQL Server 2008。表名为TableB,字段名为Value1。可以在App.config中修改数据库名称,默认名称是test。
方法一。使用基本的Insert语句。
这个方法是最基本的方法,大多数人一开始都会想到。但是Insert语句好像不太适合大规模操作吧?
该方法将100万条数据分为10批,每批包含10万条,每笔交易导入数据库10次。
-基本声明:
向TableB (Value1)中插入值(“I”);说明:语句中的I是宿主程序中的一个累加变量,用来填充数据库字段中的值。
SQL Server 2000耗时:901599
SQL Server 2008耗时:497638
方法二。使用BULK INSERT语句
这堂课的效果可以说是本次实验中最令人满意的。使用起来是最简单、最灵活、最快捷的。
“BULK INSERT”语句似乎并不常见。Aicken听说oracle中有一种方法,可以将外部文件映射到Oracle临时表中,然后将临时表中的数据直接导入到其他Oracle表中。
这种方法的速度非常令人满意。SQL SERVER的大容量插入同样令人满意吗?
-基本声明:
BULK INSERT TableB FROM '
c:\\sql.txt' WITH (FIELDTERMINATOR=',',ROWTER
/.mbMINATOR='|',BATCHSIZE=100000)
描述:“c:\\sql.txt”是一个预先生成的文件,包含100条数据,用“|”符号分隔,每100,000条数据有一个事务。
SQL Server 2000耗时:4009
SQL Server 2008耗时:10722
方法三。在多线程中使用批量插入。
在方法二的基础上,将100万条数据分五个线程,每个线程负责20万条数据,每5万条一个事物,五个线程同时启动,看看这样的效果吧。
SQL Server 2000耗时:21099
SQL Server 2008耗时:10997
方法四.使用SqlBulkCopy类
这种方法速度也很快,但是要依赖内存,对于几千万条、多字段的复杂数据,可能在内存方面会有较大的消耗,不过可以使用64位解决方案处理这个问题。
几千万条、多字段的数据的情况一般在一些业务场景中会遇到,比如计算全球消费者某个业务周期消费额时,要先获得主数据库表中的会员消费记录快照,并将快照储存至临时表中,然后供计算程序使用这些数据。
并且有些时候消费者的消费数据并不在一台数据库服务器中,而是来自多个国家的多台服务器,这样我们就必须借助内存或外存设备中转这些数据,然后清洗、合并、检测,最后导入专用表供计算程序使用。
基本语句:
using (System.Data.SqlClient.SqlBulkCopy sqlBC
=new System.Data.SqlClient.SqlBulkCopy(conn))
{ sqlBC.BatchSize=100000; sqlBC.BulkCopyTimeout
=60; sqlBC.DestinationTableName='dbo.TableB';
sqlBC.ColumnMappings.Add('valueA', 'Value1');
sqlBC.WriteToServer(dt); }
说明:
BatchSize=100000; 指示每10万条一个事务并提交
BulkCopyTimeout=60; 指示60秒按超时处理
DestinationTableName='dbo.TableB'; 指示将数据导入TableB表
ColumnMappings.Add('valueA', 'Value1'); 指示将内存中valueA字段与TableB中的Value1字段匹配
WriteToServer(dt);写入数据库。其中dt是预先构建好的DataTable,其中包含valueA字段。
SQL Server 2000耗时:4989
SQL Server 2008耗时:10412
方法五.在多线程中使用SqlBulkCopy类
基于方法四,将100万条数据分五个线程,每个线程负责20万条数据,每5万条一个事物,五个线程同时启动,看看这样的效果吧。
SQL 2000耗时:7682
SQL 2008耗时:10870
结果
几天的时间终于把这个实验给完成了,比较令人失望的是SQL SERVER 2008导入数据的性能似乎并不想我们想象的那样优秀。