首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle JDBC 分頁效能實測:從 Absolute 定位到 ROWNUM 與 Next() 的抉擇

     編輯:Oracle 資料庫基礎

前言

在處理百萬筆資料量的 Oracle 資料庫時,分頁查詢的效能往往是開發者最頭疼的問題。本文將分享實際測試過程,對比 JDBC 原生 Absolute 定位、Oracle ROWNUM 偽欄位、以及 ResultSet Next() 迴圈三種分頁方式的優劣,並探討實務上是否值得為了效能犧牲 SQL 可移植性。

測試環境與基準

  • 資料庫:Oracle 9i Release 2,西文字元集
  • 測試表:demo_table,含 100 萬筆記錄
  • 分頁場景:從不同位置(20萬、40萬、90萬)開始取一頁資料

方案一:JDBC Absolute 定位 —— 記憶體殺手

最直觀的作法是使用 ResultSet.absolute(int row) 直接跳轉到指定行。

  • 20 萬起始:耗時約 5 秒
  • 40 萬起始:直接拋出 OutOfMemoryError

結論:Oracle JDBC 實作 Absolute 時會逐行讀取並緩存前面所有資料,記憶體消耗隨定位位置線性增長,完全不適合深分頁。設定 FetchSize 僅能帶來 10% 左右的提升,治標不治本。

方案二:Oracle ROWNUM 子查詢 —— 經典但有極限

採用經典三層嵌套寫法:

SELECT * FROM (
  SELECT A.*, ROWNUM RN FROM (
    SELECT * FROM demo_table
  ) A WHERE ROWNUM <= 200010
) WHERE RN >= 200000
  • 20 萬起始:2-3 秒
  • 90 萬起始:約 13 秒

特點:隨著分頁深入,效能明顯下降,因為資料庫仍需掃描並捨棄前面所有滿足條件的行。但至少不會 OOM。

方案三:Forward-Only ResultSet + Next() 迴圈 —— 意外的發現

檢視 iBatis 原始碼發現,其分頁實作對 TYPE_FORWARD_ONLY 的 ResultSet 採用 next() 迴圈定位,而非 absolute()。實測證明:

  • 90 萬起始:約 22 秒,**無記憶體溢位**

原理:Oracle JDBC 驅動對 Forward-Only 游標的 next() 做了優化,不會將跳過的行完整物件化載入記憶體,僅在網路層面丟棄封包。雖比 ROWNUM 慢一倍,但屬同一數量級,且完全避免 OOM 風險。

實務抉擇:值得為效能犧牲跨資料庫性嗎?

綜合比較:

方案20萬90萬記憶體跨DB
Absolute5sOOM高是
ROWNUM2-3s13s低否
Next()迴圈~5s22s極低是

決策建議:

  1. 若系統極少深分頁(用戶多停留在前幾頁),保持 JDBC Next() 迴圈或標準框架分頁即可,維護性最高。
  2. 若業務確有深分頁高頻需求,才考慮 ROWNUM 或 Oracle 12c+ 的 OFFSET ... FETCH,但需接受 SQL 鎖定 Oracle。
  3. 記住:過早優化是萬惡之源。百萬表深分頁本身可能是產品設計缺陷(如缺乏搜尋/篩選),優化 SQL 不如優化業務流程。

結語

測試環境較舊(Oracle 9i),新版本驅動與資料庫對游標優化更佳。核心啟示在於:理解驅動實作機制(Absolute vs Next)比盲目追求「最快 SQL」更重要。選擇適合業務場景、可維護的方案,才是架構師的本分。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved