在上一篇文章中,我们已经讲述了一些铺垫性的知识,那么从本篇开始,就开始正式的研究批量插入性能问题。
首先来看看,我们主要测试那些东西。因为我们本系列文章是研究SqlBulkCopy与SSIS的性能,所以,我们将他们进行详细的对比。对于SqlBulkCopy,我们主要对它的一下几个属性感兴趣,因为这些属性对性能的影响很大:
Table locking:在进行批量插入数据的时候,往往会在要插入数据的表上创建一个排它锁,一方面,这个锁使得插入的更快;另一方面,也是的其他回话对此表的读取等操作都进入等待。我们会使用很多不同的场景来测试这个属性,让大家有一个比较清晰的认识。
BatchSize:这个参数主要是定义了每次批量插入的数据条数。我们发现:没有什么文档来描述这个值对性能的影响,所以,我们也会研究这个属性值。
Use Internal Transaction:其实,很多时候,很多人对SqlBulkCopy的事务都理解有误。我们通过很多的测试和实践发现,如果我们在SqlBulkCopy插入数据的时候,不用事务,速度将会非常的快,当然,这个快是牺牲其他的特性为代价的。
出了测试上面的一些属性之外,我们还会测试与批量数据的导入相关的问题,如下:
- 我们可以将数据导入到含有聚集索引的表和堆表中,看看哪一种表的导入速度最快,也看看如何更好的导入数据。
- 看看在数据导入的时候,数据库日志文件的使用情况。在使用批量导入数据的时候,不仅仅会写数据文件,还会不断的写日志,我们可以看看不同的设置和方式导致日志的大小以及其他影响。
- 使用SQL Server Trace的Flag 610 标记可以在数据批量导入的时候使得日志记录最小,这个Flag是否值得使用。
OK,下面我们就来准备测试环境。
首先,我们创建一个简单的具有6个字段的表,如下:
很显然,表中的每一行数据的大小大约是320字节。在测试的过程中,我们将会用不同的数据量来填充这个表,这个数据量会从60一直到6百万,同时也看看相关性能的数据是否有一个线性的关系。
同时,也为了测试聚集索引表和堆表,我们也会在需要的时候创建索引,如下:
我们在每次测试一个场景的时候,都会将这个表从数据库中销毁,然后重建。我们插入表中的数据都是采用随机生成的。另外,我们还会常见两种基于随机值的测试:
1. 每一个Producer(也就是数据生产者)产生的每一行数据的值都是相同的,每个字段的值肯定是随机的。可能如下:
2. 每一个Producer产生的每一行数据值都完全不同,类似如下:
之所以要进行上面两个测试,主要是要看看对于相同的数据的数据行在进行网络输入之前是否被压缩了(因为相同的数据值多次重复的出现,这就是一个很好的压缩的机会,可以大大的节省网络带宽,使得数据插入更快)。
另外,对于我们表所在的数据库,就采用最简单的日志模式,这也是绝大多数数据库采用的方式。我们不会测试SqlBulkCopy的属性与上面所有条件的所有组合,因为很多的组合的结果是可凭经验推断出来的,并且也不是所有的组合方式都对性能有影响。
为了使得测试更为的准确,在SqlBulkCopy进行数据的批量写入之前,所有的数据producers都会先把数据全部准备好,之后,再将数据传递给SqlBulkCopy。我们关注的是SqlBulkCopy写入性能,以及它对数据库的影响,请记住这一点。
下面,我们就进入第一个场景:一个consumer(数据的消费者,在这里,这个数据消费者就是SqlBulkCopy)接受6百万条数据,然后将数据导入到一个堆表中。
通过多次测试发现,consumer执行完成的时间是56秒,同时我们这里把Tablock和BatchSize的值设置为了0,同时我们发现日志文件增加了6M,如图:
在此过程中,网络的情况如下:
我们可以看看网络的使用大约25%(测试用的是1GB的带宽),也就说,没有充分的利用带宽。
另外,CPU也显示了只有一个线程在运行,没有完全的使用所有的核的功能。也就说,如果数据导入的客户端有多个核,那么我们可以增加SqlBulkCopy的数量,采用并行技术来导入数据,从而提高性能。
下面,我们就来测试上面的想法,如下:
可以看到上面的图,我们采用了4个SqlBulkCopy。
此时的网络使用如下:
此时充分的利用了带宽,并且速度也提升了300%。
今天就到这里,让大家有一个感觉!下一篇,我们接着比较更多的东西