首页 游戏 软件 资讯 排行榜 专题
首页
编程语言
怎么利用 PreparedStatement.setFetchSize() 优化从数据库读取大数据集的性能

怎么利用 PreparedStatement.setFetchSize() 优化从数据库读取大数据集的性能

热心网友
13
转载
2026-04-29

怎么利用 PreparedStatement.setFetchSize() 优化从数据库读取大数据集的性能

怎么利用 PreparedStatement.setFetchSize() 优化从数据库读取大数据集的性能

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

setFetchSize() 不是“一次查多少条”,而是“一次从网络拿多少条”

先澄清一个常见的误解:很多人以为 setFetchSize() 是给数据库下达指令,让它只返回指定数量的行。其实不然,这个参数控制的是 JDBC 驱动从数据库服务器**分批拉取结果集时,每一批要拿多少行**。它的底层逻辑,是调整网络缓冲区和内存分配的节奏,而不是去限制数据库的查询结果。

主流数据库如 MySQL 的 mysql-connector-ja va 和 PostgreSQL 的 pgjdbc 都支持这个机制,但它们的“脾气”可大不相同:MySQL 默认是关闭流式读取的,需要额外配置;而 PostgreSQL 则默认就启用了游标式获取。

  • 不设置或设为 0:驱动很可能会图省事,一次性把所有结果都加载到应用内存里,这就埋下了内存溢出(OOM)的风险。
  • 设为正整数 N:驱动会尝试按每批 N 行向数据库发送 fetch 请求。不过,它到底生不生效,还得看驱动和数据库的具体配置。
  • 对于 Oracle 数据库:除了设置 fetchSize,通常还需要确保创建 StatementPreparedStatement 时,指定 ResultSet.TYPE_FORWARD_ONLYResultSet.CONCUR_READ_ONLY 这两个参数,流式读取才能正确工作。

MySQL 下必须配 useCursorFetch=true 才能生效

这里有个大坑:MySQL 驱动默认采用的是“一次性缓存全量结果”的模式。所以,如果你只是单独调用 ps.setFetchSize(1000),完全不会起作用。必须在数据库连接 URL 中显式开启游标获取功能:

jdbc:mysql://localhost:3306/db?useCursorFetch=true

否则,哪怕你的代码写得再规范,驱动还是会固执地把几百万行数据一股脑儿全塞进堆内存,然后才允许你开始遍历 ResultSet。怎么验证配置生效了呢?一个实用的方法是观察 GC 日志或者堆内存的增长曲线——如果参数设了但没配对,内存占用依然会线性飙升。

  • 建议搭配使用:除了 useCursorFetch=true,还可以在 URL 中加上 &defaultFetchSize=1000 作为全局兜底值。
  • 注意功能限制:一旦开启游标,产生的 ResultSet 将不再支持 rs.last()rs.getRow() 这类需要随机访问的方法,因为它变成了只能向前遍历的流。
  • 事务的影响:事务隔离级别本身不影响 fetch 行为,但长时间不提交的事务可能会延长游标在服务器端的持有时间。

PostgreSQL 下 setFetchSize() 基本即开即用,但别设太大

相比之下,PostgreSQL 的 pgjdbc 驱动就“友好”多了,它默认就支持服务器端游标。调用 setFetchSize() 后,驱动会自动在后台触发 DECLARE CURSORFETCH 的流程。不过,也别高兴得太早,这里也有讲究:

  • 值不是越大越好:如果把 fetchSize 设得过大(比如超过10000),反而可能拖慢整体吞吐。虽然网络往返次数减少了,但单次传输的数据包变得非常庞大,很容易卡住 TCP 缓冲区,造成等待。
  • 经验值区间:根据多数实践,将值设置在 500 到 2000 之间是比较稳妥的。具体多少合适,还得看单行数据的大小——假设每行数据约10KB,fetchSize=1000 就意味着一次网络传输要搬运将近10MB的数据。
  • 注意查询优化:如果你的 SQL 语句中已经包含了 LIMIT 子句,驱动可能会“自作聪明”地忽略 setFetchSize(),转而采用更激进的优化策略,因为结果集本身已经被限制了。

来看一个典型的代码片段:

PreparedStatement ps = conn.prepareStatement("SELECT * FROM huge_table WHERE status = ?");
ps.setFetchSize(1000);
ps.setString(1, "active");
ResultSet rs = ps.executeQuery(); // 注意:游标声明是在执行查询这一刻才真正发起的

别忘了关闭 ResultSet 和 PreparedStatement

使用 setFetchSize() 开启流式读取后,游标资源是由数据库服务器在维持的。如果应用层没有及时关闭 ResultSet,服务器端的游标就不会被释放,久而久之可能导致数据库连接池耗尽,或者数据库直接报出 cursor not found 之类的错误。这一点在手动管理资源(而非使用 try-with-resources 语法)时尤其容易被遗漏。

  • 务必确保关闭:一定要调用 rs.close(),或者直接使用 JDK 7+ 提供的 try-with-resources 语法自动管理。
  • 级联关闭:调用 PreparedStatement.close() 通常也会级联关闭其关联的 ResultSet,但显式地进行关闭操作仍然是更可控、更推荐的做法。
  • 框架行为:像 Spring JDBC 的 JdbcTemplate 这类框架,默认会帮我们关闭资源,但如果你在自定义的 ConnectionCallback 中操作,仍需手动处理。

最后提一个最致命也最常被忽略的点:在流式读取的场景下,如果程序因为异常而提前退出,但 finally 块又没有覆盖到所有异常分支,就会导致游标资源泄漏。这个问题,往往比性能调优本身更加致命

来源:https://www.php.cn/faq/2386092.html
免责声明: 游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

相关攻略

怎么利用 PreparedStatement.setFetchSize() 优化从数据库读取大数据集的性能
编程语言
怎么利用 PreparedStatement.setFetchSize() 优化从数据库读取大数据集的性能

怎么利用 PreparedStatement setFetchSize() 优化从数据库读取大数据集的性能 setFetchSize() 不是“一次查多少条”,而是“一次从网络拿多少条” 先澄清一个常见的误解:很多人以为 setFetchSize() 是给数据库下达指令,让它只返回指定数量的行。其实

热心网友
04.29
网红白冰偷逃近千万为何没坐牢引热议:律师释疑!
业界动态
网红白冰偷逃近千万为何没坐牢引热议:律师释疑!

4000万粉丝网红偷税案:一场价值1891万的“补票” 最近,一则来自税务部门的通报引发了广泛关注。根据税收大数据分析,知名“探店”网红白冰因偷逃税款被依法查处。这再次将网络主播等高收入人群的税务合规问题,推到了聚光灯下。 案情回溯:从收入转换到虚假申报 调查显示,在2024年期间,白冰通过一系列操

热心网友
04.29
什么是网络安全?
网络安全
什么是网络安全?

导语 没有网络安全,国家安全就无从谈起,经济社会稳定运行更是空中楼阁,广大人民群众的利益也难以得到坚实的保障。因此,树立正确的网络安全观至关重要,必须未雨绸缪,加固信息基础设施的网络安全防线。 一、什么是网络安全 简单来说,网络安全是一套综合性的体系,它通过一系列工具、技术和流程,来确保组织的网络及

热心网友
04.28
mysql大数据量导出谁的速度更快_SELECT_INTO_OUTFILE性能比拼
数据库
mysql大数据量导出谁的速度更快_SELECT_INTO_OUTFILE性能比拼

MySQL大数据量导出:谁才是真正的速度王者? 当面对百万甚至千万级的数据导出任务时,选对工具往往意味着节省数小时甚至数天的等待时间。在MySQL的原生工具箱里,SELECT INTO OUTFILE 命令是那个经常被提及的“性能怪兽”。它之所以快,核心在于其极简的数据通路:由服务器线程直接

热心网友
04.28
SQL如何统计分组内不重复值的占比_结合COUNT DISTINCT计算
数据库
SQL如何统计分组内不重复值的占比_结合COUNT DISTINCT计算

SQL如何统计分组内不重复值的占比:结合COUNT DISTINCT计算 GROUP BY 后怎么算每个分组里某字段去重后的占比 直接拿 COUNT(DISTINCT ) 除以总行数,这个思路没错,但分母用错了地方——分母必须是当前分组的总行数,而不是整张表。正确的姿势是,分子用 COUNT(

热心网友
04.28

最新APP

宝宝过生日
宝宝过生日
应用辅助 04-07
台球世界
台球世界
体育竞技 04-07
解绳子
解绳子
休闲益智 04-07
骑兵冲突
骑兵冲突
棋牌策略 04-07
三国真龙传
三国真龙传
角色扮演 04-07

热门推荐

描写元旦的好句子
职业与学业
描写元旦的好句子

小编导语:新年里你一定有很多的话想要说吧!新年是一个新的开始,是一个新的期望,用很多优美的句子来描写元旦吧。更多关于新年元旦的好词好句尽在本站作文网! 新的一年如约而至。每到这个时候,总感觉一切都被按下了重启键,万物都酝酿着新的变化。长大一岁,不仅是年龄的增长,更意味着肩上多了一份沉甸甸的期许。谁都

热心网友
04.29
关于元旦的好词
职业与学业
关于元旦的好词

小编导语 新的一年翩然而至,你准备好用什么美好的词汇来装点这个崭新的开端了吗?关于元旦的精彩语汇,我们已为大家悉心整理,希望能为同学们的写作增添一抹亮色。更多关于新年元旦的绝妙好词好句,尽在本站作文网,欢迎随时取用。 说到新年,脑海里自然会浮现出一连串鲜活的画面与词汇:那是无处不在的喜庆,是家人围坐

热心网友
04.29
恩师回忆奥运冠军董栋坎坷蹦床路
职业与学业
恩师回忆奥运冠军董栋坎坷蹦床路

恩师回忆奥运冠军董栋坎坷蹦床路 伦敦奥运男子蹦床决赛的结果,想必大家还记忆犹新:中国选手董栋一举夺金,陆春龙收获铜牌,银牌则被俄罗斯选手乌萨科夫摘得。自董栋为山西省拿下这枚具有历史意义的奥运单项金牌后,他的故事便成了街头巷尾热议的话题。近日,董栋的恩师杨志强教练谈起十年前那个决定性的时刻,一切细节依

热心网友
04.29
奥运冠军王旭谈恩师:我和教练的父女情
职业与学业
奥运冠军王旭谈恩师:我和教练的父女情

奥运冠军王旭谈恩师:我和教练的父女情 2004年雅典奥运会女子摔跤72公斤级的领奖台上,王旭的名字被历史铭记。然而,金牌的光芒背后,有一段鲜为人知却更为动人的故事。夺冠那一刻,王旭与教练许奎元紧紧相拥,这位北京姑娘赛后的一句话道出了所有:“这块金牌,实现了我们两个人的梦想。” 在当时的国家摔跤队里,

热心网友
04.29
王羲之书圣卖“当”
职业与学业
王羲之书圣卖“当”

王羲之书圣卖“当” 提起王羲之,这位东晋书坛的巅峰人物,历代学书者无不奉其为圭臬,尊一声“书圣”。他不仅字写得好,生平逸事也颇为有趣。话说有一年春天,王羲之兴致勃勃地去杭州访友,途经苏州时,被江南的夜色深深吸引,流连忘返。晚风拂面,醉意与美景交融,谁料欣赏了一夜风景后,他竟一病不起。 书童赶忙请来苏

热心网友
04.29