server多笔记录拼接字符串 sql_Java拼接“1亿行字符串”你会遇到什么问题?
拼接“1億行字符串”你會(huì)遇到什么問(wèn)題?
本文將涉及到的三方面的內(nèi)容,如下:
1,一個(gè)10萬(wàn)次的for循環(huán),4種實(shí)現(xiàn)的性能對(duì)比
2,直接將For循環(huán)改為1億次,遇到的問(wèn)題
3,拓展
00. 需求
原計(jì)劃是生成1億條模擬數(shù)據(jù),詳細(xì)的需求如下:
創(chuàng)建1億條Insert SQL語(yǔ)句,例如:INSERT INTO products (`id`,`code`) value (1, '000000000');其中,id 類型為INT(11)code 類型為VARCHAR(9),值區(qū)間00000000-99999999,長(zhǎng)度不足9位的在前面補(bǔ)充0使其長(zhǎng)度滿足9位。01. 一個(gè)10萬(wàn)次的for循環(huán),4種實(shí)現(xiàn)的性能對(duì)比
最終目的是1億,但是會(huì)涉及到時(shí)間消耗問(wèn)題,所以計(jì)劃先從10萬(wàn)行數(shù)據(jù)開(kāi)始查看一下實(shí)現(xiàn)方式上的效率對(duì)別。決定使用方式之后將數(shù)據(jù)量升級(jí)到1億行最終實(shí)現(xiàn)需求。
選擇了日常代碼中經(jīng)常見(jiàn)到的4種方式實(shí)現(xiàn)方式:
1, 使用 “+” 來(lái)拼接字符串; 2,使用StringBuffer | StringBuilder來(lái)拼接字符串; 3,使用String.formate() 來(lái)格式化字符串,并用 “+” 拼接字符串; 4,使用String.formate() 來(lái)格式化字符串,并用 StringBuffer | StringBuilder 拼接字符串;在10萬(wàn)數(shù)據(jù)時(shí)候當(dāng)前場(chǎng)景它們各自的執(zhí)行效率如何呢,下面是統(tǒng)計(jì)后的對(duì)比
代碼結(jié)構(gòu)如下:
對(duì)代碼感興趣同學(xué)可以看 這里;
整體性能的對(duì)比結(jié)果很顯然:
StringBuilder > "+"拼接 > String.formate()
使用 “+” 拼接字符串,雖然底層的實(shí)現(xiàn)使用StringBuilder做了優(yōu)化,并不是直接用 “+” 拼接 直接代替StringBuilder那么簡(jiǎn)單。
一次 “+”字符串拼接,相當(dāng)于執(zhí)行
new StringBuilder(str).append(newStr).toString();例如:
String name = "P" + "a" + "g" + "e";相當(dāng)于
String name = new StringBuilder(new StringBuilder(new StringBuilder("P").append("a").toString()).append("g").toString()).append("e").toString();使用上面的方法測(cè)試不同數(shù)量級(jí)的運(yùn)行時(shí)間得到如下參考數(shù)據(jù):
整個(gè)過(guò)程中會(huì)多次創(chuàng)建新的對(duì)象,并頻繁調(diào)用toString()方法,最終導(dǎo)致了其性能的下降。
通過(guò)上面的結(jié)果我們可以得到如下結(jié)果:
1,在上面需求的復(fù)雜度的情況下,小于1000條數(shù)據(jù)時(shí),選擇哪種實(shí)現(xiàn)均可,可以優(yōu)先考慮可讀性,所以可以優(yōu)先考慮String.formate();2,在上面需求的復(fù)雜度的情況下,大于1000條數(shù)據(jù)時(shí),優(yōu)先考慮StringBuilder或String.formate()。String.formate()通常能夠帶來(lái)更好的可讀性,但是如果性能上造成了很大的困擾時(shí),請(qǐng)考慮使用StringBuilder;3,如果場(chǎng)景不是足夠簡(jiǎn)單,盡量避免使用“+”拼接字符串,因?yàn)樗葲](méi)有帶來(lái)很好的可讀性,也沒(méi)帶來(lái)很好的性能。02. 目標(biāo)1個(gè)億
上面數(shù)據(jù)量只到了100,000(即:10萬(wàn))條,而我們的目標(biāo)是100,000,000(即:1億)條。
通過(guò)100條 - 10萬(wàn)條數(shù)據(jù)的過(guò)程,我們字符串拼接的性能并不是線程增長(zhǎng)的,在10W的時(shí)候:
(1)“+”已經(jīng)達(dá)到38s,一次可以推斷 1億條記錄至少 38s x 1000 ≈ 10.5h。 (2)StringBuilder只用了43ms,所以它可能帶給我們驚喜。 (3)String.formate + StringBuilder消耗了532ms,1億條記錄至少 0.532s x 1000 ≈ 532s(9分多鐘)
所以直接使用方案2來(lái)StringBuffer生成SQL語(yǔ)句是個(gè)好選擇,直接將循環(huán)測(cè)試設(shè)為為1億次。
當(dāng)將循環(huán)次數(shù)設(shè)定為循環(huán)1億次時(shí),卻出了出了問(wèn)題。
Exception in thread "main" java.lang.OutOfMemoryError: Java heap spaceJVM可以通過(guò)-Xms和-Xmx來(lái)設(shè)定堆內(nèi)存。在經(jīng)過(guò)幾次測(cè)試之后得到如下參考數(shù)據(jù):
很顯然一臺(tái)內(nèi)存是16GB的MacBook Pro是無(wú)法滿足直接在內(nèi)存中創(chuàng)建1億行Insert SQL語(yǔ)句的。那么如何完成上述需求?
既然無(wú)法通過(guò)1個(gè)1一次的For循環(huán)來(lái)生成,那么可以通過(guò)多個(gè)多次的For循環(huán),比如執(zhí)行10次1千萬(wàn)的For循環(huán)。按照上面的思路,執(zhí)行了兩次操作: 1,執(zhí)行10次,每次生成1000萬(wàn)行數(shù)據(jù),并將生成數(shù)據(jù)持久化的同一個(gè)文件。 2,執(zhí)行10次,每次生成1000萬(wàn)行數(shù)據(jù),并將生成數(shù)據(jù)持久化的一個(gè)獨(dú)立的文件。 3,執(zhí)行100次,每次生成100萬(wàn)行數(shù)據(jù),并將生成數(shù)據(jù)持久化的一個(gè)獨(dú)立的文件。
執(zhí)行結(jié)果如下:
到此為止需求實(shí)現(xiàn)。
03. 拓展
1,如果一開(kāi)始選擇實(shí)現(xiàn)方式是每生成一條SQL就append到文件中,那么上面的部分問(wèn)題你不會(huì)遇到。
2,在生成測(cè)試數(shù)據(jù)時(shí),如果數(shù)據(jù)比1億條更大,那么需要注意StringBuilder內(nèi)部有一個(gè)capacity,capacity的類型為int,因此存在最大capacity的限制,另外
3,StringBuilder內(nèi)部會(huì)有byte[]實(shí)現(xiàn),處理大數(shù)據(jù)量是還需要關(guān)注數(shù)組越界的問(wèn)題。
4,最終生成的文件大小可以在實(shí)際應(yīng)用中需要進(jìn)行判斷,使用何種體積的文件,建議使用每個(gè)文件100萬(wàn)行數(shù)據(jù)體積64.9MB的文件,因?yàn)榇蜷_(kāi)這個(gè)體積的文本文件速度較快(無(wú)論是通過(guò)Vim還是文本工具)。
5,在處理的大量數(shù)據(jù)時(shí),除了關(guān)注可讀性可讀性,同時(shí)還需要關(guān)注效率以及,需要時(shí)還需要關(guān)注JVM參數(shù)設(shè)置。
總結(jié)
以上是生活随笔為你收集整理的server多笔记录拼接字符串 sql_Java拼接“1亿行字符串”你会遇到什么问题?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: elementui 按钮 表单_前后端分
- 下一篇: asp获取ftp服务器目录并显示_用 P