JDBC批量讀取優化-fetchSize


(一)場景與方案

  場景:java端從數據庫讀取100W數據進行后台業務處理。

  常規實現1:分頁讀取出來。缺點:需要排序后分頁讀取,性能低下。

  常規實現2:一次性讀取出來。缺點:需要很大內存,一般計算機不行。

  非常規實現:建立長連接,利用服務端游標,一條一條流式返回給java端。

  非常規實現優化:jdbc中有個重要的參數fetchSize(它對業務實現無影響,即不會限制讀取條數等),優化后可顯著提升性能。

(二)代碼與執行結果

public static void main(String[] args) throws SQLException {
        getAll(1);
        getAll(10);
        getAll(100);
        getAll(1000);
    }

public static void getAll(int fetchSize) {
        try {
            long beginTime=System.currentTimeMillis();

            Connection connection = DriverManager.getConnection(MYSQL_URL);
            connection.setAutoCommit(false); //為了設置fetchSize,必須設置為false
            String sql = "select * from test";
            PreparedStatement psst = connection.prepareStatement(sql,ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
            psst.setFetchSize(fetchSize);
            ResultSet rs = psst.executeQuery();

            int totalCount=0;
            while (rs.next()) {
                    totalCount++;
            }
            rs.close();
            psst.close();
            connection.close();

            long endTime=System.currentTimeMillis();
            System.out.println("totalCount:"+totalCount+";fetchSize:"+fetchSize+";耗時:"+(endTime-beginTime)+"ms");
        } catch (SQLException e) {
            e.printStackTrace();
        } 
    }

  執行結果如下——

totalCount:3185194;fetchSize:1;耗時:23770ms
totalCount:3185194;fetchSize:10;耗時:23253ms
totalCount:3185194;fetchSize:100;耗時:21890ms
totalCount:3185194;fetchSize:1000;耗時:20985ms

  可以看到,當fetchSize為1000時,性能有提升。(看一些網友的數據,性能提升更多)

 

(三)原理分析

1、先在服務端執行查詢后將數據緩存在服務端。(耗時相對較長)

2、java端獲取數據時,利用服務端游標進行指針跳動,如果fetchSize為1000,則一次性跳動1000條,返回給java端緩存起來。(耗時較短,跳動次數為N/1000)

3、在調用next函數時,優先從緩存中取數,其次執行2過程。(內存讀取,耗時可忽略)

題外話:spring的JdbcCursorItemReader是對fetchSize的良好應用。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM