成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

被問傻了:從MySQL讀取100w數據進行處理,怎么做?

數據庫 MySQL
默認情況下,完整的檢索結果集會將其存儲在內存中。在大多數情況下,這是最有效的操作方式,并且由于 MySQL 網絡協議的設計,因此更易于實現。

大數據量操作的場景大致如下:

  • 數據遷移
  • 數據導出
  • 批量處理數據

在實際工作中當指定查詢數據過大時,我們一般使用分頁查詢的方式一頁一頁的將數據放到內存處理。但有些情況不需要分頁的方式查詢數據或分很大一頁查詢數據時,如果一下子將數據全部加載出來到內存中,很可能會發生OOM(內存溢出);而且查詢會很慢,因為框架耗費大量的時間和內存,去把數據庫查詢的結果封裝成我們想要的對象(實體類)。

舉例:在業務系統需要從 MySQL 數據庫里讀取 100w 數據行進行處理,應該怎么做?

做法通常如下:

  • 常規查詢: 一次性讀取 100w 數據到 JVM 內存中,或者分頁讀取
  • 流式查詢:建立長連接,利用服務端游標,每次讀取一條加載到 JVM 內存(多次獲取,一次一行)
  • 游標查詢: 和流式一樣,通過 fetchSize 參數,控制一次讀取多少條數據(多次獲取,一次多行)

一、常規查詢

默認情況下,完整的檢索結果集會將其存儲在內存中。在大多數情況下,這是最有效的操作方式,并且由于 MySQL 網絡協議的設計,因此更易于實現。

舉例:假設單表 100w 數據量,一般會采用分頁的方式查詢:

@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。

該方式比較簡單,如果在不考慮 LIMIT 深分頁優化情況下,估計你的數據庫服務器就噶皮了,或者你能等上幾十分鐘或幾小時,甚至幾天時間檢索數據。

二、流式查詢

流式查詢指的是查詢成功后不是返回一個集合而是返回一個迭代器,應用每次從迭代器取一條查詢結果。流式查詢的好處是能夠降低內存使用。

如果沒有流式查詢,我們想要從數據庫取 100w 條記錄而又沒有足夠的內存時,就不得不分頁查詢,而分頁查詢效率取決于表設計,如果設計的不好,就無法執行高效的分頁查詢。因此流式查詢是一個數據庫訪問框架必須具備的功能。

MyBatis 中使用流式查詢避免數據量過大導致 OOM ,但在流式查詢的過程當中,數據庫連接是保持打開狀態的,因此要注意的是:

  • 執行一個流式查詢后,數據庫訪問框架就不負責關閉數據庫連接了,需要應用在取完數據后自己關閉
  • 必須先讀?。ɑ蜿P閉)結果集中的所有行,然后才能對連接發出任何其他查詢,否則將引發異常

MyBatis 流式查詢接口

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

  • Cursor 是可關閉的
  • Cursor 是可遍歷的

除此之外,Cursor 還提供了三個方法:

  • isOpen(): 用于在取數據之前判斷 Cursor 對象是否是打開狀態。只有當打開時 Cursor 才能取數據
  • isConsumed(): 用于判斷查詢結果是否全部取完
  • getCurrentIndex(): 返回已經獲取了多少條數據

使用流式查詢,則要保持對產生結果集的語句所引用的表的并發訪問,因為其查詢會獨占連接,所以必須盡快處理。

為什么要用流式查詢?

如果有一個很大的查詢結果需要遍歷處理,又不想一次性將結果集裝入客戶端內存,就可以考慮使用流式查詢。

分庫分表場景下,單個表的查詢結果集雖然不大,但如果某個查詢跨了多個庫多個表,又要做結果集的合并、排序等動作,依然有可能撐爆內存;詳細研究了sharding-sphere的代碼不難發現,除了group by與order by字段不一樣之外,其他的場景都非常適合使用流式查詢,可以最大限度的降低對客戶端內存的消耗。

三、游標查詢

對大量數據進行處理時,為防止內存泄漏情況發生,也可以采用游標方式進行數據查詢處理。這種處理方式比常規查詢要快很多。

當查詢百萬級的數據的時候,還可以使用游標方式進行數據查詢處理,不僅可以節省內存的消耗,而且還不需要一次性取出所有數據,可以進行逐條處理或逐條取出部分批量處理。一次查詢指定 fetchSize 的數據,直到把數據全部處理完。

Mybatis 的處理加了兩個注解:@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:結果集的游標只能向下滾動
  • ResultSet.SCROLL_INSENSITIVE:結果集的游標可以上下移動,當數據庫變化時,當前結果集不變
  • ResultSet.SCROLL_SENSITIVE:返回可滾動的結果集,當數據庫變化時,當前結果集同步改變
  • fetchSize:每次獲取量

@ResultType

  • @ResultType(BigDataSearchEntity.class):轉換成返回實體類型

注意:返回類型必須為 void ,因為查詢的結果在 ResultHandler 里處理數據,所以這個 hander 也是必須的,可以使用 lambda 實現一個依次處理邏輯。

注意:

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

  • 方式一是多次查詢,一次返回多條
  • 方式二是一次查詢,一次返回一條

原因:

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

MySQL 是在執行 ResultSet.next() 方法時,會通過數據庫連接一條一條的返回。flush buffer 的過程是阻塞式的,如果網絡中發生了擁塞,send buffer 被填滿,會導致 buffer 一直 flush 不出去,那 MySQL 的處理線程會阻塞,從而避免數據把客戶端內存撐爆。

非流式查詢和流式查詢區別:

  • 非流式查詢:內存會隨著查詢記錄的增長而近乎直線增長
  • 流式查詢:內存會保持穩定,不會隨著記錄的增長而增長。其內存大小取決于批處理大小BATCH_SIZE的設置,該尺寸越大,內存會越大。所以BATCH_SIZE應該根據業務情況設置合適的大小

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

責任編輯:武曉燕 來源: JAVA日知錄
相關推薦

2021-06-23 06:48:42

秒殺Java電商

2019-08-23 09:03:04

盤口數據數據庫緩存

2025-06-03 02:10:00

2023-09-27 22:44:18

數據遷移數據庫

2021-07-09 05:52:36

架構開發緩存

2024-09-05 21:24:02

數據庫查詢MySQLlimit

2019-09-16 09:34:39

2011-04-06 14:50:05

SQL查詢效率

2022-11-16 17:10:25

MySQL數據事務

2016-06-28 10:13:04

華為開發者大賽

2020-07-28 08:36:54

數據安全數據泄露數據

2011-03-11 09:53:46

FacebookMySQL

2017-11-08 12:25:37

小程序運營公眾號

2022-03-10 11:25:51

InnoDB優化

2016-01-05 16:17:59

云夢數據倉

2018-02-07 09:00:09

2021-10-12 10:22:33

數據庫架構技術

2021-11-10 05:00:58

數據分析運營

2015-09-20 18:31:29

阿里云心電數據云上安心
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 成人一区二区三区在线观看 | 日韩激情在线 | 日韩免费一区二区 | 中文字幕一页二页 | 欧美a在线看| 国产精品1 | 羞羞视频免费在线观看 | 国产成人a亚洲精品 | 日韩欧美在线视频一区 | 高清黄色网址 | 欧美一级三级在线观看 | 日韩精品在线播放 | 亚洲成人精品 | 伊人精品国产 | 亚洲精选久久 | 1000部精品久久久久久久久 | 日韩综合在线播放 | av在线播放免费 | 色婷婷久久久亚洲一区二区三区 | 97免费在线视频 | 亚洲欧美一区二区三区在线 | 超碰高清| 免费观看一级特黄欧美大片 | caoporn国产| 黄色日本视频 | 久久久久久影院 | 亚洲精品一区中文字幕乱码 | 国产乱码一二三区精品 | 涩涩99 | 日本一区二区三区四区 | 性高湖久久久久久久久aaaaa | 欧美成人二区 | 国产一区不卡 | 欧美日韩综合视频 | 成人中文字幕在线观看 | 99精品亚洲国产精品久久不卡 | 啪视频在线 | 国产黄色在线观看 | 超碰成人免费 | 成人在线免费看 | 国产在线视频一区二区董小宛性色 |