亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

MyBatisPlus?大數(shù)據(jù)量查詢(xún)慢的問(wèn)題解決

 更新時(shí)間:2023年02月05日 08:35:09   作者:曠野歷程  
本文主要介紹了MyBatis?Plus?解決大數(shù)據(jù)量查詢(xún)慢問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

大數(shù)據(jù)量操作的場(chǎng)景大致如下:

  • 數(shù)據(jù)遷移
  • 數(shù)據(jù)導(dǎo)出
  • 批量處理數(shù)據(jù)

在實(shí)際工作中當(dāng)指定查詢(xún)數(shù)據(jù)過(guò)大時(shí),我們一般使用分頁(yè)查詢(xún)的方式一頁(yè)一頁(yè)的將數(shù)據(jù)放到內(nèi)存處理。但有些情況不需要分頁(yè)的方式查詢(xún)數(shù)據(jù)或分很大一頁(yè)查詢(xún)數(shù)據(jù)時(shí),如果一下子將數(shù)據(jù)全部加載出來(lái)到內(nèi)存中,很可能會(huì)發(fā)生OOM(內(nèi)存溢出);而且查詢(xún)會(huì)很慢,因?yàn)榭蚣芎馁M(fèi)大量的時(shí)間和內(nèi)存去把數(shù)據(jù)庫(kù)查詢(xún)的結(jié)果封裝成我們想要的對(duì)象(實(shí)體類(lèi))。

舉例:在業(yè)務(wù)系統(tǒng)需要從 MySQL 數(shù)據(jù)庫(kù)里讀取 100w 數(shù)據(jù)行進(jìn)行處理,應(yīng)該怎么做?

做法通常如下:

  • 常規(guī)查詢(xún):一次性讀取 100w 數(shù)據(jù)到 JVM 內(nèi)存中,或者分頁(yè)讀取
  • 流式查詢(xún):建立長(zhǎng)連接,利用服務(wù)端游標(biāo),每次讀取一條加載到 JVM 內(nèi)存(多次獲取,一次一行)
  • 游標(biāo)查詢(xún):和流式一樣,通過(guò) fetchSize 參數(shù),控制一次讀取多少條數(shù)據(jù)(多次獲取,一次多行)

常規(guī)查詢(xún)

默認(rèn)情況下,完整的檢索結(jié)果集會(huì)將其存儲(chǔ)在內(nèi)存中。在大多數(shù)情況下,這是最有效的操作方式,并且由于 MySQL 網(wǎng)絡(luò)協(xié)議的設(shè)計(jì),因此更易于實(shí)現(xiàn)。

舉例:

假設(shè)單表 100w 數(shù)據(jù)量,一般會(huì)采用分頁(yè)的方式查詢(xún):

@Mapper
public interface BigDataSearchMapper extends BaseMapper<BigDataSearchEntity> {
 
    @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")
    Page<BigDataSearchEntity> pageList(@Param("page") Page<BigDataSearchEntity> page, @Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper);
 
}

注:該示例使用的 MybatisPlus 

該方式比較簡(jiǎn)單,如果在不考慮 LIMIT 深分頁(yè)優(yōu)化情況下,估計(jì)你的數(shù)據(jù)庫(kù)服務(wù)器就噶皮了,或者你能等上幾十分鐘或幾小時(shí),甚至幾天時(shí)間檢索數(shù)據(jù)

流式查詢(xún)

流式查詢(xún)指的是查詢(xún)成功后不是返回一個(gè)集合而是返回一個(gè)迭代器,應(yīng)用每次從迭代器取一條查詢(xún)結(jié)果。流式查詢(xún)的好處是能夠降低內(nèi)存使用。如果沒(méi)有流式查詢(xún),我們想要從數(shù)據(jù)庫(kù)取 100w 條記錄而又沒(méi)有足夠的內(nèi)存時(shí),就不得不分頁(yè)查詢(xún),而分頁(yè)查詢(xún)效率取決于表設(shè)計(jì),如果設(shè)計(jì)的不好,就無(wú)法執(zhí)行高效的分頁(yè)查詢(xún)。因此流式查詢(xún)是一個(gè)數(shù)據(jù)庫(kù)訪問(wèn)框架必須具備的功能。

MyBatis 中使用流式查詢(xún)避免數(shù)據(jù)量過(guò)大導(dǎo)致 OOM ,但在流式查詢(xún)的過(guò)程當(dāng)中,數(shù)據(jù)庫(kù)連接是保持打開(kāi)狀態(tài)的,因此要注意的是:

  • 執(zhí)行一個(gè)流式查詢(xún)后,數(shù)據(jù)庫(kù)訪問(wèn)框架就不負(fù)責(zé)關(guān)閉數(shù)據(jù)庫(kù)連接了,需要應(yīng)用在取完數(shù)據(jù)后自己關(guān)閉。
  • 必須先讀取(或關(guān)閉)結(jié)果集中的所有行,然后才能對(duì)連接發(fā)出任何其他查詢(xún),否則將引發(fā)異常。

MyBatis 流式查詢(xún)接口

MyBatis 提供了一個(gè)叫 org.apache.ibatis.cursor.Cursor 的接口類(lèi)用于流式查詢(xún),這個(gè)接口繼承了 java.io.Closeable 和 java.lang.Iterable 接口,由此可知:

  • Cursor 是可關(guān)閉的;
  • Cursor 是可遍歷的。

除此之外,Cursor 還提供了三個(gè)方法:

  • isOpen():用于在取數(shù)據(jù)之前判斷 Cursor 對(duì)象是否是打開(kāi)狀態(tài)。只有當(dāng)打開(kāi)時(shí) Cursor 才能取數(shù)據(jù);
  • isConsumed():用于判斷查詢(xún)結(jié)果是否全部取完。
  • getCurrentIndex():返回已經(jīng)獲取了多少條數(shù)據(jù)

使用流式查詢(xún),則要保持對(duì)產(chǎn)生結(jié)果集的語(yǔ)句所引用的表的并發(fā)訪問(wèn),因?yàn)槠?查詢(xún)會(huì)獨(dú)占連接,所以必須盡快處理

為什么要用流式查詢(xún)?

  • 如果有一個(gè)很大的查詢(xún)結(jié)果需要遍歷處理,又不想一次性將結(jié)果集裝入客戶(hù)端內(nèi)存,就可以考慮使用流式查詢(xún);
  • 分庫(kù)分表場(chǎng)景下,單個(gè)表的查詢(xún)結(jié)果集雖然不大,但如果某個(gè)查詢(xún)跨了多個(gè)庫(kù)多個(gè)表,又要做結(jié)果集的合并、排序等動(dòng)作,依然有可能撐爆內(nèi)存;詳細(xì)研究了sharding-sphere的代碼不難發(fā)現(xiàn),除了group by與order by字段不一樣之外,其他的場(chǎng)景都非常適合使用流式查詢(xún),可以最大限度的降低對(duì)客戶(hù)端內(nèi)存的消耗。

關(guān)于流式查詢(xún)查詢(xún)小編本人了解不是很多,再此就不過(guò)多說(shuō)明,如果發(fā)現(xiàn)好的資源,還請(qǐng)留言讓小編也學(xué)習(xí)一下。

游標(biāo)查詢(xún)

對(duì)大量數(shù)據(jù)進(jìn)行處理時(shí),為防止內(nèi)存泄漏情況發(fā)生,也可以采用游標(biāo)方式進(jìn)行數(shù)據(jù)查詢(xún)處理。這種處理方式比常規(guī)查詢(xún)要快很多。

當(dāng)查詢(xún)百萬(wàn)級(jí)的數(shù)據(jù)的時(shí)候,還可以使用游標(biāo)方式進(jìn)行數(shù)據(jù)查詢(xún)處理,不僅可以節(jié)省內(nèi)存的消耗,而且還不需要一次性取出所有數(shù)據(jù),可以進(jìn)行逐條處理或逐條取出部分批量處理。一次查詢(xún)指定 fetchSize 的數(shù)據(jù),直到把數(shù)據(jù)全部處理完。

Mybatis 的處理加了兩個(gè)注解: @Options 和 @ResultType

@Mapper
public interface BigDataSearchMapper extends BaseMapper<BigDataSearchEntity> {
 
    // 方式一 多次獲取,一次多行
    @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 1000000)
    Page<BigDataSearchEntity> pageList(@Param("page") Page<BigDataSearchEntity> page, @Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper);
 
    // 方式二 一次獲取,一次一行
    @Select("SELECT bds.* FROM big_data_search bds ${ew.customSqlSegment} ")
    @Options(resultSetType = ResultSetType.FORWARD_ONLY, fetchSize = 100000)
    @ResultType(BigDataSearchEntity.class)
    void listData(@Param(Constants.WRAPPER) QueryWrapper<BigDataSearchEntity> queryWrapper, ResultHandler<BigDataSearchEntity> handler);
 
}

@Options

  • ResultSet.FORWORD_ONLY:結(jié)果集的游標(biāo)只能向下滾動(dòng)
  • ResultSet. SCROLL_INSENSITIVE:結(jié)果集的游標(biāo)可以上下移動(dòng),當(dāng)數(shù)據(jù)庫(kù)變化時(shí),當(dāng)前結(jié)果集不變
  • ResultSet.SCROLL_SENSITIVE:返回可滾動(dòng)的結(jié)果集,當(dāng)數(shù)據(jù)庫(kù)變化時(shí),當(dāng)前結(jié)果集同步改變
  • fetchSize:每次獲取量

@ResultType

  • @ResultType(BigDataSearchEntity.class):轉(zhuǎn)換成返回實(shí)體類(lèi)型

注意: 返回類(lèi)型必須為 void ,因?yàn)椴樵?xún)的結(jié)果在 ResultHandler 里處理數(shù)據(jù),所以這個(gè) hander 也是必須的,可以使用 lambda 實(shí)現(xiàn)一個(gè)依次處理邏輯。

注意:

雖然上面的代碼中都有 @Options 但實(shí)際操作卻有不同:

  • 方式一是多次查詢(xún),一次返回多條;
  • 方式二是一次查詢(xún),一次返回一條;

原因:

Oracle 是從服務(wù)器一次取出 fetch size 條記錄放在客戶(hù)端,客戶(hù)端處理完成一個(gè)批次后再向服務(wù)器取下一個(gè)批次,直到所有數(shù)據(jù)處理完成。

MySQL 是在執(zhí)行 ResultSet.next() 方法時(shí),會(huì)通過(guò)數(shù)據(jù)庫(kù)連接一條一條的返回。flush buffer 的過(guò)程是阻塞式的,如果網(wǎng)絡(luò)中發(fā)生了擁塞,send buffer 被填滿(mǎn),會(huì)導(dǎo)致 buffer 一直 flush 不出去,那 MySQL 的處理線程會(huì)阻塞,從而避免數(shù)據(jù)把客戶(hù)端內(nèi)存撐爆。

非流式查詢(xún)和流式查詢(xún)區(qū)別:

  • 非流式查詢(xún):內(nèi)存會(huì)隨著查詢(xún)記錄的增長(zhǎng)而近乎直線增長(zhǎng)。
  • 流式查詢(xún):內(nèi)存會(huì)保持穩(wěn)定,不會(huì)隨著記錄的增長(zhǎng)而增長(zhǎng)。其內(nèi)存大小取決于批處理大小BATCH_SIZE的設(shè)置,該尺寸越大,內(nèi)存會(huì)越大。所以BATCH_SIZE應(yīng)該根據(jù)業(yè)務(wù)情況設(shè)置合適的大小。

另外要切記每次處理完一批結(jié)果要記得釋放存儲(chǔ)每批數(shù)據(jù)的臨時(shí)容器,即上文中的gxids.clear();

到此這篇關(guān)于MyBatisPlus 大數(shù)據(jù)量查詢(xún)慢的問(wèn)題解決的文章就介紹到這了,更多相關(guān)MyBatisPlus查詢(xún)慢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java行為型設(shè)計(jì)模式之模板方法詳解

    Java行為型設(shè)計(jì)模式之模板方法詳解

    模板方法的概念:定義了一個(gè)操作中的算法的骨架,而將部分步驟的實(shí)現(xiàn)在子類(lèi)中完成。模板方法模式使得子類(lèi)可以不改變一個(gè)算法的結(jié)構(gòu)即可重定義該算法的某些特定步驟
    2022-09-09
  • Springboot3整合Mybatis3的完整步驟記錄

    Springboot3整合Mybatis3的完整步驟記錄

    這篇文章主要給大家介紹了關(guān)于Springboot3整合Mybatis3的完整步驟,Spring Boot和MyBatis分別是兩個(gè)功能強(qiáng)大的框架,它們的協(xié)同使用可以極大地簡(jiǎn)化數(shù)據(jù)訪問(wèn)層的開(kāi)發(fā),提高整體的開(kāi)發(fā)效率,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • Tomcat數(shù)據(jù)源配置方法_JBuilder中

    Tomcat數(shù)據(jù)源配置方法_JBuilder中

    今天幫一同事配置一個(gè)數(shù)據(jù)源,采用tomcat5.5.9,本來(lái)是個(gè)很簡(jiǎn)單的事,以前也配過(guò),但由于很長(zhǎng)時(shí)間沒(méi)用過(guò)容器提供的數(shù)據(jù)源了(IOC用慣了),也只記的個(gè)大概了,所以剛開(kāi)始一配就出錯(cuò)了,google了一下,有很多資料,照著試試卻都不好使(到不是別人說(shuō)的不對(duì),只是大家用的版本不同)。
    2008-10-10
  • Spring中BeanFactory?FactoryBean和ObjectFactory的三種的區(qū)別

    Spring中BeanFactory?FactoryBean和ObjectFactory的三種的區(qū)別

    關(guān)于FactoryBean?和?BeanFactory的對(duì)比文章比較多,但是對(duì)ObjectFactory的描述就比較少,今天我們對(duì)比下這三種的區(qū)別,感興趣的朋友跟隨小編一起看看吧
    2023-01-01
  • SpringBoot整合RabbitMQ, 實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者的功能

    SpringBoot整合RabbitMQ, 實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者的功能

    這篇文章主要介紹了SpringBoot整合RabbitMQ, 實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者的功能,幫助大家更好得理解和學(xué)習(xí)使用SpringBoot框架,感興趣的朋友可以了解下
    2021-03-03
  • Java中的WeakHashMap簡(jiǎn)析

    Java中的WeakHashMap簡(jiǎn)析

    這篇文章主要介紹了Java中的WeakHashMap簡(jiǎn)析,Map 的子類(lèi)常見(jiàn)的有 HashMap、Hashtable、ConcurrentHashMap、LinkedHashMap 等,WeakHashMap,直譯就是,虛弱的 HashMap,從名字可得知其和 HashMap 有關(guān),需要的朋友可以參考下
    2023-09-09
  • java中的BlockingQueue(阻塞隊(duì)列)解析

    java中的BlockingQueue(阻塞隊(duì)列)解析

    這篇文章主要介紹了java中的BlockingQueue阻塞隊(duì)列解析,阻塞隊(duì)列是一個(gè)支持兩個(gè)附加操作的隊(duì)列,這兩個(gè)附加的操作是,在隊(duì)列為空時(shí),獲取元素的線程會(huì)等待隊(duì)列變?yōu)榉强?需要的朋友可以參考下
    2023-12-12
  • Java TreeSet類(lèi)的簡(jiǎn)單理解和使用

    Java TreeSet類(lèi)的簡(jiǎn)單理解和使用

    這篇文章主要介紹了Java TreeSet類(lèi)的簡(jiǎn)單理解和使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java多線程之volatile關(guān)鍵字及內(nèi)存屏障實(shí)例解析

    Java多線程之volatile關(guān)鍵字及內(nèi)存屏障實(shí)例解析

    volatile是JVM提供的一種最輕量級(jí)的同步機(jī)制,因?yàn)镴ava內(nèi)存模型為volatile定義特殊的訪問(wèn)規(guī)則,使其可以實(shí)現(xiàn)Java內(nèi)存模型中的兩大特性:可見(jiàn)性和有序性。這篇文章主要介紹了Java多線程之volatile關(guān)鍵字及內(nèi)存屏障,需要的朋友可以參考下
    2019-05-05
  • 深入解析Java的Struts框架中的控制器DispatchAction

    深入解析Java的Struts框架中的控制器DispatchAction

    這篇文章主要介紹了深入解析Java的Struts框架中的控制器DispatchAction,Struts是Java的SSH三大web開(kāi)發(fā)框架之一,需要的朋友可以參考下
    2015-12-12

最新評(píng)論