JDBC讀取數(shù)據(jù)優(yōu)化-fetchsize

最近由于業(yè)務上的需求,一張舊表結構中的數(shù)據(jù),需要提取出來,根據(jù)規(guī)則,導入一張新表結構中,開發(fā)同學寫了一個工具,用于實現(xiàn)新舊結構的transformation,

成都創(chuàng)新互聯(lián)從2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術服務公司,擁有項目成都網(wǎng)站設計、成都網(wǎng)站制作網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元湘西土家族做網(wǎng)站,已為上家服務,為湘西土家族各地企業(yè)和個人服務,聯(lián)系電話:18980820575

實現(xiàn)邏輯簡單,就是使用jdbc從A表讀出數(shù)據(jù),做了一些處理,再存入新表B中,發(fā)現(xiàn)讀取舊表的操作,非常緩慢,無法滿足要求。

讀取數(shù)據(jù)的示例代碼,

conn = getConnection();
long start = System.currentTimeMillis();
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
long mid_end = System.currentTimeMillis();
while (rs.next()) {
    list.add(rs.getString(1));
}
long end = System.currentTimeMillis();
rs.close();
System.out.println("Interval1=" + (mid_end - start));
System.out.println("Interval2=" + (end - mid_end));

SQL語句讀取10000條記錄,其中,

Interval1=160ms
Interval2=29252ms

執(zhí)行executeQuery()這個SQL檢索的時間為160毫秒。

執(zhí)行10000次rs.next以及rs.getString(1)的用時約為30秒,平均1條記錄3毫秒。

如何才能提高讀取的效率?

上面讀取10000條記錄,每一次rs.next時間只有3毫秒,但是由于需要10000次,所以才需要30秒,我們可以猜測,是否有可能每一次rs.next的執(zhí)行,均需要和數(shù)據(jù)庫交互,因為如果僅是字符串操作,不應該是這個數(shù)量級。

看一下官方文檔的描述,《Database JDBC Developer's Guide》有一節(jié)介紹了Fetch Size,

By default, when Oracle JDBC runs a query, it retrieves a result set of 10 rows at a time from the database cursor. This is the default Oracle row fetch size value. You can change the number of rows retrieved with each trip to the database cursor by changing the row fetch size value.

Standard JDBC also enables you to specify the number of rows fetched with each database round-trip for a query, and this number is referred to as the fetch size. In Oracle JDBC, the row-prefetch value is used as the default fetch size in a statement object. Setting the fetch size overrides the row-prefetch setting and affects subsequent queries run through that statement object.

Fetch size is also used in a result set. When the statement object run a query, the fetch size of the statement object is passed to the result set object produced by the query. However, you can also set the fetch size in the result set object to override the statement fetch size that was passed to it.

Changes made to the fetch size of a statement object after a result set is produced will have no affect on that result set.

JDBC默認每執(zhí)行一次檢索,會從游標中提取10行記錄,10就是默認的row fetch size值,通過設置row fetch size,可以改變每次和數(shù)據(jù)庫交互,提取出來的記錄行總數(shù)。需要注意的是,需要在獲得檢索結果集之前,設置fetch size,否則就是無效。

可以使用如下方法設置,

Setting the Fetch Size

The following methods are available in all Statement, PreparedStatement, CallableStatement, and ResultSet objects for setting and getting the fetch size:

  • void setFetchSize(int rows) throws SQLException

  • int getFetchSize() throws SQLException

簡單來講,F(xiàn)etch相當于讀緩存,默認Fetch Size值是10,讀取10000條記錄,一次數(shù)據(jù)庫交互,即rs.next的操作,ResultSet會一次性從數(shù)據(jù)庫服務器,得到10條記錄,下次執(zhí)行rs.next,就直接使用內存讀取,不用和數(shù)據(jù)庫交互了,但總計需要有1000次交互,如果使用setFetchSize設置Fetch Size為10000,則只需要一次數(shù)據(jù)庫交互,本地緩存10000條記錄,每次執(zhí)行rs.next,只是內存操作,不會有數(shù)據(jù)庫網(wǎng)絡消耗,效率就會高些。但需要注意的是,F(xiàn)etch Size值越高則占用內存越高,要避免出現(xiàn)OOM錯誤。

方案1:


rs = ps.executeQuery();
rs.setFetchSize(10000);

即在執(zhí)行ps.executeQuery()之后,對rs設置值10000,統(tǒng)計如下,

執(zhí)行executeQuery()這個SQL檢索的時間為174毫秒。

執(zhí)行10000次rs.next以及rs.getString(1)的用時約為190毫秒。

相比之前執(zhí)行10000次rs.next,用了30秒,提高了將近150倍。


方案2:


ps = conn.prepareStatement(sql);
ps.setFetchSize(10000);

即在執(zhí)行conn.prepareStatement(sql)之后,執(zhí)行ps.executeQuery()之前,對rs設置值為10000范圍,統(tǒng)計如下,

執(zhí)行executeQuery()這個SQL檢索的時間為267毫秒。

執(zhí)行10000次rs.next以及rs.getString(1)的用時約為87毫秒。

相比方案2,總用時幾乎一致,但SQL執(zhí)行和rs.next遍歷的用時,有些區(qū)別。


針對方案1,

After you have run the query, you can call  setFetchSize  on the result set object to override the statement object fetch size that was passed to it. This will affect any subsequent trips to the database to get more rows for the original query, as well as affecting any later refetching of rows.

執(zhí)行查詢之后,對結果集設置setFetchSize,會影響任何接下來的數(shù)據(jù)庫交互過程獲得更多的記錄行數(shù),以及之后的fetch提取。

針對方案2,

To set the fetch size for a query, call  setFetchSize  on the statement object prior to running the query. If you set the fetch size to N, then N rows are fetched with each trip to the database.

執(zhí)行查詢之前,設置setFetchSize,表示每次和數(shù)據(jù)庫交互,得到記錄行數(shù)。

綜上所述,建議執(zhí)行SQL之前,設置此值,效率提升最高。

對于PrepareStatement、ResultSet和Statement,均有這一個方法,有一點出入的,就是默認值設置(0),從代碼中使用getFetchSize(),得到的值均為10,不知道是我理解錯了,還是有其他含義?歡迎各位指教。

PrepareStatement

  • setFetchSize

    void setFetchSize(int rows)
              throws SQLException

    Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for  ResultSet objects generated by this  Statement . If the value specified is zero, then the hint is ignored. The default value is zero.

    • Parameters:

    • rows - the number of rows to fetch

    • Throws:

    • SQLException - if a database access error occurs, this method is called on a closed Statement or the condition rows >= 0 is not satisfied.

    • Since:

    • 1.2

    • See Also:

    • getFetchSize()

ResultSet

  • setFetchSize

    void setFetchSize(int rows)
              throws SQLException

    Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for this  ResultSet  object. If the fetch size specified is zero, the JDBC driver ignores the value and is free to make its own best guess as to what the fetch size should be.  The default value is set by the  Statement  object that created the result set.  The fetch size may be changed at any time.

    • Parameters:

    • rows - the number of rows to fetch

    • Throws:

    • SQLException - if a database access error occurs; this method is called on a closed result set or the condition rows >= 0 is not satisfied

    • Since:

    • 1.2

    • See Also:

    • getFetchSize()

Statement

  • setFetchSize

    void setFetchSize(int rows)
              throws SQLException

    Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for  ResultSet objects generated by this  Statement . If the value specified is zero, then the hint is ignored. The default value is zero.

    • Parameters:

    • rows - the number of rows to fetch

    • Throws:

    • SQLException - if a database access error occurs, this method is called on a closed Statement or the condition rows >= 0 is not satisfied.

    • Since:

    • 1.2

    • See Also:

    • getFetchSize()

總結:

1. Fetch相當于讀緩存,如果使用setFetchSize設置Fetch Size為10000,本地緩存10000條記錄,每次執(zhí)行rs.next,只是內存操作,不會有數(shù)據(jù)庫網(wǎng)絡消耗,效率就會高些。但需要注意的是,F(xiàn)etch Size值越高則占用內存越高,要避免出現(xiàn)OOM錯誤。

2. 建議執(zhí)行SQL語句之前設置,即ps.executeQuery();之前使用setFetchSize()函數(shù)設置。

分享文章:JDBC讀取數(shù)據(jù)優(yōu)化-fetchsize
本文路徑:http://www.muchs.cn/article16/pieggg.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設ChatGPT、動態(tài)網(wǎng)站自適應網(wǎng)站、微信公眾號標簽優(yōu)化

廣告

聲明:本網(wǎng)站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設公司