原因及解决方法

直接说原因:Oracle JDBC驱动默认的fetchSize为10,每次只会提取fetchSize条记录到客户端。因此可以调大mybatis xml文件的fetchSize属性来减少网络开销。

1
2
3
<select id="queryData" resultMap="BaseResultMap" fetchSize="1000">
...
</select>

如果是SpringBoot程序,直接添加一项全局配置,数字大小看实际情况决定
mybatis.configuration.default-fetch-size=100

背景

最近接到一个任务,要给合作厂商开发接口,他们提供Oracle视图和存储过程,相当于已经设计好了数据库,我们开发后台。

遇到问题

如题,开发时发现“Oracle在数据库软件下sql查询很快,但是在程序中查询很慢”,http接口测试要5、6秒。刚开始怀疑是网络问题,毕竟不在同一个公司,网络传输是比较慢的,但是想想sql执行只要几十毫秒,这说不过去。

于是开始搜索,网上真是各种不靠谱的答案一堆:

  1. 映射字段类型不一致
  2. 用了for循环查sql
  3. 线程池不够
  4. sql发生了改变,没走索引

诸如此类,一眼丁真,非常离谱

直到在知乎看到这个答案才恍然大悟, 想起以前学习JDBC时还遇到过,MySQL从没遇到过要设置fetchSize,时间太久给忘了这个参数

1
Oracle JDBC驱动默认的fetchSize为10,每次网络报会传送fetchSize条记录到客户端。可以调大fetchSize看看有没有效果。

调整过参数之后速度快了近百倍,只要50~100ms完成接口查询。

MySQL是为什么这么快的

经常一番查找发现:默认情况下,MySQL的JDBC驱动会一下子把所有row都读取下来,相当于设置了一个很大的fetchSize, 这点和Oracle完全相反。

总结

在实际开发中,MySQL的默认配置更加合理些。数据少时两者没多大区别,数据大了,更应该减少网络开销才是,或者进行分页查询等手段优化。

一次性获取全部数据压力在后台程序,可以通过负载均衡等手段减轻压力,但如果fetchSize太小,后台程序和数据库都会承受压力,而实际要获取的数据并不会因此减少,整体体验更差。

解决方法:见开头