開心一笑
【跟我媽說(shuō)這幾天特別郁悶,心情糟透了。
我媽說(shuō):要不我給你拿錢你出去玩幾天??!
我立馬笑顏逐開:“好啊好啊”!
媽:“開心了吧”!
我:“嗯嗯,媽,快點(diǎn)拿錢呀!”
媽:“你都開心了我還拿錢干啥!”
我。。?!?/p>
提出問(wèn)題
真實(shí)項(xiàng)目中,批量插入數(shù)據(jù)性能優(yōu)化???
解決問(wèn)題
1.業(yè)務(wù)場(chǎng)景
1.1 業(yè)務(wù)描述
數(shù)據(jù)庫(kù)有一張表(pm_testcase),客戶有一份excel數(shù)據(jù),里面有3+萬(wàn)條左右案例?,F(xiàn)在需要解析excel里面的內(nèi)容,對(duì)每條數(shù)據(jù)進(jìn)行校驗(yàn)。比如:名稱長(zhǎng)度校驗(yàn),編號(hào)校驗(yàn),用戶賬號(hào)是否存在檢驗(yàn)等等。然后封裝成 List 集合,批量保存。
CREATE TABLE "public"."pm_testcase" (
"id" varchar(32) COLLATE "default" NOT NULL,
"code" varchar(50) COLLATE "default",
"name" varchar(200) COLLATE "default",
//....省略若干個(gè)字段
CONSTRAINT "pk_pm_testcase" PRIMARY KEY ("id")
)
WITH (OIDS=FALSE)
;
1.2 業(yè)務(wù)流程圖
2.項(xiàng)目現(xiàn)狀
2.1 問(wèn)題一
在excel數(shù)據(jù)導(dǎo)入,循環(huán) List 集合,進(jìn)行校驗(yàn)時(shí),存在大量的連接數(shù)據(jù)庫(kù)操作。
//循環(huán)excel的每一行
for (int j = sheet.getFirstRowNum() + 1,len = sheet.getLastRowNum(); j <= len; j++) {
Row row = sheet.getRow(j);
if (row == null) continue;
if (StringUtils.isEmpty(getValue(row.getCell(6)))) resultBuffer.append("案例類型為空,");
//....省略其他校驗(yàn)操作...
//連接數(shù)據(jù)庫(kù)
SysUser sysUser = sysUserService.findById(id);
}
2.2 問(wèn)題二
直接批量保存3萬(wàn)多條數(shù)據(jù)。
List<PcsTestcase> pcsTestcases = new ArrayList<>();
// ......
//直接調(diào)用批量保存
this.batchCreate(pcsTestcases);
2.3 問(wèn)題三
批量保存時(shí),利用UUID生成工具,給主鍵設(shè)置Id。找出Hibernate的先查詢后更新的機(jī)制觸發(fā),造成不必要的查詢損耗。
List<PcsTestcase> pcsTestcases = new ArrayList<>();
PcsTestcase pcsTestcase = null;
for (int j = sheet.getFirstRowNum() + 1,len = sheet.getLastRowNum(); j <= len;j++) {
Row row = sheet.getRow(j);
if (row == null) continue;
pcsTestcase = new PcsTestcase();
//看這里,重要:這里在插入數(shù)據(jù)時(shí),設(shè)置主鍵Id
pcsTestcase.setId(UUIDUtils.generate());
pcsTestcase.setPmMilestoneId(pcsMainTask.getId());
}
3. 解決方法
3.1 問(wèn)題一解決方法
對(duì)于問(wèn)題一,除了避免在 for 循環(huán)體內(nèi)連接數(shù)據(jù)庫(kù)外,我們可以利用 Map集合的緩存機(jī)制,把之后需要用到的數(shù)據(jù)加載到map集合中。比如:依次性查詢出所有的用戶數(shù)據(jù)等等,存放在Map集合中。
3.2 問(wèn)題二解決方法
對(duì)于問(wèn)題二,我們可以把所有數(shù)據(jù),每500條進(jìn)行一次批量保存操作,速度會(huì)比一次性批量保存好。具體如下:
if(j % 500 == 0 || j == len){
this.batchCreate(pcsTestcases);
pcsTestcases = new ArrayList<>();
}
3.3 問(wèn)題三解決方法
對(duì)于問(wèn)題三,由于Hibernate在進(jìn)行插入時(shí),會(huì)判斷數(shù)據(jù)是進(jìn)行插入還是進(jìn)行更新。如果模型的主鍵不為空,查詢數(shù)據(jù)后,再進(jìn)行更新數(shù)據(jù),否則,進(jìn)行插入數(shù)據(jù)操作。因此,我們?cè)谶M(jìn)行插入操作時(shí)候,不要設(shè)置模型的主鍵,可以避免不必要查詢消耗。
pcsTestcase.setId(UUIDUtils.generate());
基本的優(yōu)化思路就是這樣了,大功告成~~~
讀書感悟
來(lái)自北宋名相寇準(zhǔn)《六悔銘》,教人要及早覺悟悔改
- 六悔銘
官行私曲,失時(shí)悔。
富不儉用,貧時(shí)悔。
藝不少學(xué),過(guò)時(shí)悔。
見事不學(xué),用時(shí)悔。
醉發(fā)狂言,醒時(shí)悔。
安不將息,病時(shí)悔。
經(jīng)典故事
【一教授與農(nóng)民在火車上相對(duì)而坐,無(wú)聊之際。教授說(shuō):我出一道題,你若不知,給我5元,如果你出一道題,我若不知,給你500元如何?農(nóng)民同意。教授問(wèn):月亮距地球多遠(yuǎn)?農(nóng)民一言不發(fā)遞給教授5元。農(nóng)民問(wèn):上山三條腿,下山四條腿,是什么動(dòng)物?教授苦思無(wú)解,無(wú)奈給農(nóng)民500元。農(nóng)民接過(guò)錢準(zhǔn)備睡覺。教授追問(wèn):上山三條腿,下山四條腿究竟是什么動(dòng)物?農(nóng)民一言不發(fā)遞給教授5元錢,然后睡覺了。低學(xué)歷高智商,太可怕了!這就是許多沒(méi)學(xué)歷的人能成為老板,首富的原因?!?/p>
大神文章
【1】【Java/JDBC.ORM】 jdbc插入大量數(shù)據(jù)時(shí)優(yōu)化處理
【2】Hibernate批處理操作優(yōu)化 (批量插入、更新與刪除)
【3】用Java向數(shù)據(jù)庫(kù)中插入大量數(shù)據(jù)時(shí)的優(yōu)化
其他
如果有帶給你一絲絲小快樂(lè),就讓快樂(lè)繼續(xù)傳遞下去,歡迎點(diǎn)贊、頂、歡迎留下寶貴的意見、多謝支持!