PG jdbc 驅動的cursor 的使用
商城轉pg 有個索引的功能模組,
之前在oracle 端的做法是根據rownum 分頁讀取的,每次10w 筆記錄。
轉到pg後,也是採用了這個方式,似乎就不太湊效了。
如果不用order by 排序,直接使用limit m,n 每次返回10w筆記錄,似乎會有重複的資料。
第一次返回的部分記錄會在第二次返回的記錄集中出現。導致索引不太準確。 於是加了order by 來排序
然後用limit m,n 返回記錄。結果加了這個排序後,效率低的嚇人,第一個10w筆還是可以接受,之後的,就實在是無法忍受了。
於是建議開發同事用遊標的方式來提取資料,這樣就不用排序了,也不用多次執行sql語句了。
開發同事做了實驗:
[code]
Connection conn = ((DataSource) EnvUtils.getEnv().getApplicationContext().getBean("dataSource")).getConnection();
PreparedStatement pst = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
pst.setFetchSize(10000);
java.lang.OutOfMemoryError: Java heap space
[/code]
記憶體溢位了,雖然我們設定了每次fetch 1w筆記錄,似乎是把整個資料庫裡的記錄全部都取出來了。
原因在哪裡呢,於是去專門看了pg的jdbc 驅動的doc。
問題終於找到了。
pg 裡如果要使用cursor 功能來批次處理資料,需要開啟事務功能。
pg 的jdbc 的doc 裡給了一個例子:
[code]
之前在oracle 端的做法是根據rownum 分頁讀取的,每次10w 筆記錄。
轉到pg後,也是採用了這個方式,似乎就不太湊效了。
如果不用order by 排序,直接使用limit m,n 每次返回10w筆記錄,似乎會有重複的資料。
第一次返回的部分記錄會在第二次返回的記錄集中出現。導致索引不太準確。 於是加了order by 來排序
然後用limit m,n 返回記錄。結果加了這個排序後,效率低的嚇人,第一個10w筆還是可以接受,之後的,就實在是無法忍受了。
於是建議開發同事用遊標的方式來提取資料,這樣就不用排序了,也不用多次執行sql語句了。
開發同事做了實驗:
[code]
Connection conn = ((DataSource) EnvUtils.getEnv().getApplicationContext().getBean("dataSource")).getConnection();
PreparedStatement pst = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
pst.setFetchSize(10000);
java.lang.OutOfMemoryError: Java heap space
[/code]
記憶體溢位了,雖然我們設定了每次fetch 1w筆記錄,似乎是把整個資料庫裡的記錄全部都取出來了。
原因在哪裡呢,於是去專門看了pg的jdbc 驅動的doc。
問題終於找到了。
pg 裡如果要使用cursor 功能來批次處理資料,需要開啟事務功能。
pg 的jdbc 的doc 裡給了一個例子:
[code]
Example 5.2. Setting fetch size to turn cursors on and off.
Changing code to cursor mode is as simple as setting the fetch size of the Statement to the appropriate size. Setting the fetch size back to 0 will cause all rows to be cached (the default behaviour).
// make sure autocommit is off conn.setAutoCommit(false); Statement st = conn.createStatement(); // Turn use of the cursor on. st.setFetchSize(50); ResultSet rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) { System.out.print("a row was returned."); } rs.close(); // Turn the cursor off. st.setFetchSize(0); rs = st.executeQuery("SELECT * FROM mytable"); while (rs.next()) { System.out.print("many rows were returned."); } rs.close(); // Close the statement. st.close();
[/code]
按此方法請開發同事測試了下,果然給力。
於是動手改造了索引的這部分程式碼,90W 記錄,完成索引大約10分鐘。
而之前order by limit m,n 版本的 在測試環境跑了一個下午。 差距很大。
記於此,為後來者指路。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/133735/viewspace-733295/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 尋MYSQL 的JDBC驅動jar??MySqlJDBCJAR
- Oracle的JDBC驅動的版本說明OracleJDBC
- oracle中jdbc驅動包的說明OracleJDBC
- maven打包oracle jdbc驅動MavenOracleJDBC
- 檢視JDBC驅動版本JDBC
- oracle11g jdbc新的驅動包OracleJDBC
- Mysql java JDBC驅動jar包MySqlJavaJDBCJAR
- Sybase15驅動包的問題com.sybase.jdbc3.jdbc.SybDriverJDBC
- 有這個資料庫的JDBC的驅動程式嗎?資料庫JDBC
- JDBC概述以及幾種驅動程式JDBC
- 聊聊pg jdbc的queryTimeout及next方法JDBC
- Oracle JDBC驅動使用setDate()、setTimestamp()導致全表掃描OracleJDBC
- DBVisualizer 新增資料庫JDBC驅動資料庫JDBC
- JDBC的使用JDBC
- 慎用或儘量不要用微軟自帶的sqlserver的jdbc驅動 (轉)微軟SQLServerJDBC
- jdbc的資料庫驅動類DriverManager.getConnection()引數JDBC資料庫
- 各種資料庫的jdbc驅動下載及連線方式資料庫JDBC
- JBuilder9 和 SQL2000 driver for JDBC的驅動配置UISQLJDBC
- 沒想到,JDBC 驅動會偷偷修改 sql_mode 的會話值JDBCSQL會話
- 簡單測試動態遊標(REF CURSOR)的使用
- 【YashanDB知識庫】YashanDB的JDBC/OCI驅動如何設定字元編碼JDBC字元
- 關於Oracle OCI驅動的使用Oracle
- Cursor使用
- 小特性 大用途 —— YashanDB JDBC驅動的這些特性你都get了嗎?JDBC
- oracle12c jdbc驅動版本使用注意事項:ora-28040:沒有匹配的驗證協議OracleJDBC協議
- 各種資料庫的JDBC驅動下載及連線字串URL寫法資料庫JDBC字串
- SQLServer2000 JDBC驅動的完整安裝及測試說明 (轉)SQLServerJDBC
- JDBC驅動程式Maven依賴項大全列表 - Vlad MihalceaJDBCMaven
- JDBC使用PreparedStatement的好處JDBC
- 查詢程式使用的cursor 數量
- MySQL的驅動表與被驅動表MySql
- Laravel驅動管理類Manager的分析和使用Laravel
- MySQL JDBC驅動版本與資料庫版本的對應關係及注意事項MySqlJDBC資料庫
- postgres的邏輯備份還原:pg_dump和pg_restore的使用REST
- 用jdbc for sqlserver2000驅動怎麼設url啊?JDBCSQLServer
- 事件驅動的微服務-事件驅動設計事件微服務
- JDBC的初步瞭解及使用JDBC
- oracle中cursor的使用經典資料Oracle