您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Mybatis大數(shù)據(jù)量批量寫優(yōu)化的方法是什么”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
在項(xiàng)目中使用批量數(shù)據(jù)插入,經(jīng)常會(huì)用到 mybatis的 foreach,如下:
<insert id="batchInsert" parameterType="java.util.List"> insert into USER (id, name) values <foreach collection="list" item="model" index="index" separator=","> (#{model.id}, #{model.name}) </foreach> </insert>
就是將
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
轉(zhuǎn)換成
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"), ("data1", "data2"), ("data1", "data2"), ("data1", "data2"), ("data1", "data2");
從理論上將,復(fù)用conn,將多次io,轉(zhuǎn)換成一次io,應(yīng)該是提升效率的。但是實(shí)際上當(dāng)數(shù)據(jù)量比較大的時(shí)候,用foreach效率非常低,速度非常慢
當(dāng)表的列數(shù)較多(20+),以及一次性插入的行數(shù)較多(5000+)時(shí),整個(gè)插入的耗時(shí)十分漫長,達(dá)到了14分鐘,這是不能忍的
那為什么使用使用foreach效率如此之低呢??
Mybatis默認(rèn)執(zhí)行器類型為Simple,默認(rèn)會(huì)為每一個(gè)sql產(chǎn)生一個(gè)PrepareStatement,而且對(duì)于foreach無法使用緩存。如果字段和行數(shù)非常多,那么sql必然也會(huì)很長,占位符也會(huì)非常多,除此之外還要建立占位符和參數(shù)之間的映射,那么解析時(shí)間必然會(huì)長。因此如果values行數(shù)越多,那么解析時(shí)間必然很長。執(zhí)行效率低。
如果非要使用 foreach 的方式來進(jìn)行批量插入的話,可以考慮減少一條 insert 語句中 values 的個(gè)數(shù),最好能達(dá)到上面曲線的最底部的值,使速度最快。一般按經(jīng)驗(yàn)來說,一次性插20~50行數(shù)量是比較合適的,時(shí)間消耗也能接受。
那么如果要用批量插入,改如何優(yōu)化呢?
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH); try { SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class); List<SimpleTableRecord> records = getRecordsToInsert(); // not shown BatchInsert<SimpleTableRecord> batchInsert = insert(records) .into(simpleTable) .map(id).toProperty("id") .map(firstName).toProperty("firstName") .map(lastName).toProperty("lastName") .map(birthDate).toProperty("birthDate") .map(employed).toProperty("employed") .map(occupation).toProperty("occupation") .build() .render(RenderingStrategy.MYBATIS3); batchInsert.insertStatements().stream().forEach(mapper::insert); session.commit(); } finally { session.close(); }
基本思想是將 MyBatis session 的 executor type 設(shè)為 Batch ,然后通過遍歷多次執(zhí)行插入語句
就類似于JDBC的下面語句一樣。
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true","root","root"); connection.setAutoCommit(false); PreparedStatement ps = connection.prepareStatement( "insert into tb_user (name) values(?)"); for (int i = 0; i < stuNum; i++) { ps.setString(1,name); ps.addBatch(); } ps.executeBatch(); connection.commit(); connection.close();
Mybatis內(nèi)置的ExecutorType有3種,默認(rèn)的是simple單句模式,該模式下它為每個(gè)語句的執(zhí)行創(chuàng)建一個(gè)新的預(yù)處理語句,單句提交sql;batch模式重復(fù)使用已經(jīng)預(yù)處理的語句,并且批量執(zhí)行所有語句,大批量模式下性能更優(yōu)。
請(qǐng)注意batch模式在Insert操作時(shí)事務(wù)沒有提交之前,是沒有辦法獲取到自增的id,所以請(qǐng)根據(jù)業(yè)務(wù)情況使用。
使用simple模式提交10000條數(shù)據(jù),時(shí)間為19s,batch模式為6s ,大致情況如此,優(yōu)化的具體還要看提交的語句情況。
如果需要使用 foreach來優(yōu)化數(shù)據(jù)插入的話,需要將每次插入的記錄控制在 10-100 左右是比較快的,建議每次100來分割數(shù)據(jù),也就是分而治之思想。
默認(rèn)的插入方式是遍歷insert語句,單條執(zhí)行,效率肯定低下,如果成堆插入,更是性能有問題。
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"); INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
如果要優(yōu)化插入速度時(shí),可以將許多小型操作組合到一個(gè)大型操作中。理想情況下,這樣可以在單個(gè)連接中一次性發(fā)送許多新行的數(shù)據(jù),并將所有索引更新和一致性檢查延遲到最后才進(jìn)行。
<insert id="batchInsert" parameterType="java.util.List"> insert into table1 (field1, field2) values <foreach collection="list" item="t" index="index" separator=","> (#{t.field1}, #{t.field2}) </foreach> </insert>
翻譯成sql語句也就是
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2"), ("data1", "data2"), ("data1", "data2"), ("data1", "data2"), ("data1", "data2");
“Mybatis大數(shù)據(jù)量批量寫優(yōu)化的方法是什么”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。