200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > server多笔记录拼接字符串 sql_Java拼接“1亿行字符串”你会遇到什么问题?

server多笔记录拼接字符串 sql_Java拼接“1亿行字符串”你会遇到什么问题?

时间:2018-10-17 22:27:37

相关推荐

server多笔记录拼接字符串 sql_Java拼接“1亿行字符串”你会遇到什么问题?

拼接“1亿行字符串”你会遇到什么问题?

本文将涉及到的三方面的内容,如下:

1,一个10万次的for循环,4种实现的性能对比

2,直接将For循环改为1亿次,遇到的问题

3,拓展

00. 需求

原计划是生成1亿条模拟数据,详细的需求如下:

创建1亿条Insert SQL语句,例如:INSERT INTO products (`id`,`code`) value (1, '000000000');其中,id 类型为INT(11)code 类型为VARCHAR(9),值区间00000000-99999999,长度不足9位的在前面补充0使其长度满足9位。

01. 一个10万次的for循环,4种实现的性能对比

最终目的是1亿,但是会涉及到时间消耗问题,所以计划先从10万行数据开始查看一下实现方式上的效率对别。决定使用方式之后将数据量升级到1亿行最终实现需求。

选择了日常代码中经常见到的4种方式实现方式:

1, 使用 “+” 来拼接字符串;2,使用StringBuffer | StringBuilder来拼接字符串;3,使用String.formate() 来格式化字符串,并用 “+” 拼接字符串;4,使用String.formate() 来格式化字符串,并用 StringBuffer | StringBuilder 拼接字符串;

在10万数据时候当前场景它们各自的执行效率如何呢,下面是统计后的对比

代码结构如下:

对代码感兴趣同学可以看这里;

整体性能的对比结果很显然:

StringBuilder>"+"拼接>String.formate()

使用 “+” 拼接字符串,虽然底层的实现使用StringBuilder做了优化,并不是直接用 “+” 拼接 直接代替StringBuilder那么简单。

一次 “+”字符串拼接,相当于执行

new StringBuilder(str).append(newStr).toString();

例如:

String name = "P" + "a" + "g" + "e";

相当于

String name = new StringBuilder(new StringBuilder(new StringBuilder("P").append("a").toString()).append("g").toString()).append("e").toString();

使用上面的方法测试不同数量级的运行时间得到如下参考数据:

整个过程中会多次创建新的对象,并频繁调用toString()方法,最终导致了其性能的下降。

通过上面的结果我们可以得到如下结果:

1,在上面需求的复杂度的情况下,小于1000条数据时,选择哪种实现均可,可以优先考虑可读性,所以可以优先考虑String.formate();2,在上面需求的复杂度的情况下,大于1000条数据时,优先考虑StringBuilder或String.formate()。String.formate()通常能够带来更好的可读性,但是如果性能上造成了很大的困扰时,请考虑使用StringBuilder;3,如果场景不是足够简单,尽量避免使用“+”拼接字符串,因为它既没有带来很好的可读性,也没带来很好的性能。

02. 目标1个亿

上面数据量只到了100,000(即:10万)条,而我们的目标是100,000,000(即:1亿)条。

通过100条 - 10万条数据的过程,我们字符串拼接的性能并不是线程增长的,在10W的时候:

(1)“+”已经达到38s,一次可以推断 1亿条记录至少 38s x 1000 ≈ 10.5h。 (2)StringBuilder只用了43ms,所以它可能带给我们惊喜。 (3)String.formate + StringBuilder消耗了532ms,1亿条记录至少 0.532s x 1000 ≈ 532s(9分多钟)

所以直接使用方案2来StringBuffer生成SQL语句是个好选择,直接将循环测试设为为1亿次。

当将循环次数设定为循环1亿次时,却出了出了问题。

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

JVM可以通过-Xms和-Xmx来设定堆内存。在经过几次测试之后得到如下参考数据:

很显然一台内存是16GB的MacBook Pro是无法满足直接在内存中创建1亿行Insert SQL语句的。那么如何完成上述需求?

既然无法通过1个1一次的For循环来生成,那么可以通过多个多次的For循环,比如执行10次1千万的For循环。

按照上面的思路,执行了两次操作: 1,执行10次,每次生成1000万行数据,并将生成数据持久化的同一个文件。 2,执行10次,每次生成1000万行数据,并将生成数据持久化的一个独立的文件。 3,执行100次,每次生成100万行数据,并将生成数据持久化的一个独立的文件。

执行结果如下:

到此为止需求实现。

03. 拓展

1,如果一开始选择实现方式是每生成一条SQL就append到文件中,那么上面的部分问题你不会遇到。

2,在生成测试数据时,如果数据比1亿条更大,那么需要注意StringBuilder内部有一个capacity,capacity的类型为int,因此存在最大capacity的限制,另外

3,StringBuilder内部会有byte[]实现,处理大数据量是还需要关注数组越界的问题。

4,最终生成的文件大小可以在实际应用中需要进行判断,使用何种体积的文件,建议使用每个文件100万行数据体积64.9MB的文件,因为打开这个体积的文本文件速度较快(无论是通过Vim还是文本工具)。

5,在处理的大量数据时,除了关注可读性可读性,同时还需要关注效率以及,需要时还需要关注JVM参数设置。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。