bigywater.tech
Java · 317

JDBC 游标与 Fetch Size

为什么 setFetchSize 有时不起作用?读百万行的结果集怎么不把堆撑爆?PostgreSQL 与 MySQL 的做法差在哪里?这篇用 128 MB 的堆限制把每种配置跑一遍。

OutOfMemoryError
-Xmx128m 下 PostgreSQL 的 fetchSize=1000 + autocommit=true(被忽略)读 200 万行的结果
4899 ms
PostgreSQL fetchSize=10(autocommit=false)读完 200 万行的耗时,fetchSize=1000 时是 524 ms
577 vs 1561 ms
MySQL 流式读取与 useCursorFetch 读完 200 万行的耗时

PostgreSQL

实测 · 本机执行输出
  fetchSize=0(默认),autocommit=true          OutOfMemoryError(已读 0 行;堆峰值 126 MB;用时 948 ms)
  fetchSize=1000,autocommit=true           OutOfMemoryError(已读 0 行;堆峰值 127 MB;用时 854 ms)
  fetchSize=1000,autocommit=false          读完 2000000 行;第一行 99 ms;总耗时 524 ms;堆峰值 75 MB
  fetchSize=10,autocommit=false            读完 2000000 行;第一行 98 ms;总耗时 4899 ms;堆峰值 76 MB
  fetchSize=100000,autocommit=false        读完 2000000 行;第一行 118 ms;总耗时 451 ms;堆峰值 84 MB

MySQL

实测 · 本机执行输出
  默认(fetchSize=0)                                  Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
  setFetchSize(1000) 但没有 useCursorFetch            Exception in thread "Thread-0" java.lang.OutOfMemoryError: Java heap space
  setFetchSize(Integer.MIN_VALUE)(流式)              读完 2000000 行;第一行 137 ms;总耗时 577 ms;堆峰值 70 MB
  useCursorFetch=true + fetchSize=1000             读完 2000000 行;第一行 818 ms;总耗时 1561 ms;堆峰值 71 MB
  useCursorFetch=true + fetchSize=1000,autocommit=false 读完 2000000 行;第一行 817 ms;总耗时 1556 ms;堆峰值 68 MB

放宽堆之后

实测 · 本机执行输出
  fetchSize=0,autocommit=true,-Xmx2g         读完 2000000 行;第一行 381 ms;总耗时 461 ms;堆峰值 270 MB
  fetchSize=1000,autocommit=false,-Xmx2g     读完 2000000 行;第一行 99 ms;总耗时 526 ms;堆峰值 133 MB

分步演示

JDBC fetchSize
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,-Xmx128m(第三节 -Xmx2g);自己起的 PostgreSQL 16.15 与 MySQL 26.7.0(端口 9501 / 9601,127.0.0.1),用户自己的数据库没有被使用;pgjdbc 42.7.4、mysql-connector-j 9.1.0;每个配置只跑一次;堆峰值是每 20 ms 采样到的已用堆(含未回收垃圾)
    • 没有验证:有 LOB / 宽行时的结果、多个结果集并发读取、游标在服务器端的资源占用与超时、TYPE_SCROLL_INSENSITIVE 结果集、网络延迟较大时的 fetchSize 取舍、连接池对 autocommit 的影响
    京ICP备2026067502号-1京公网安备11010502063487号