java项目中db查询超时思考

232 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

项目运行中经常会遇到db查询超时,这时候大家往往都会想到去优化sql,但是今天我想说的一个观点是查询超时可能不是sql语句问题也可能是orm框架问题

环境

  • orm:mybatis-plus
  • db: mysql
  • 数据量 132w

测试

这时候我们用这样sql查询 select * from stu 也就是全表扫描

代码如下:


LambdaQueryWrapper<Student> lambdaQuery = getLambdaQuery();
lambdaQuery.select(Student::getClassNo);

baseMapper.selectList(lambdaQuery);

执行打印如下

SQL:[SELECT class_no FROM student] 执行耗时 [6240ms]

此时我修改代码

LambdaQueryWrapper<Student> lambdaQuery = getLambdaQuery();
lambdaQuery.select(Student::getClassNo);

baseMapper.selectObjs(lambdaQuery);

执行打印如下

SQL:[SELECT class_no FROM student] 执行耗时 [1870ms]

发现了什么?sql语句都是一样的但是查询相差整整5s

思考

这时候区别就在于 第一个查询是直接出来的封装后的对象,第二个查询的只是obj

我们都知道orm其中一个作用就是将数据库的字段和我们的类属性形成映射关系,将行数据组装成对象,那么其实第二个方式跳过了这个部分,直接就是放入了一个list中万事了,第一种方式是要一个反射调用赋值的过程

可以验证下

验证

用arthas 的 trace 功能区验证

首先经过不断的打断点调试,关键的代码如下

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
  PreparedStatement ps = (PreparedStatement) statement;
  // db查询
  ps.execute();
  // 数据赋值
  return resultSetHandler.handleResultSets(ps);
}

这时候用arthas 的trace 命令分别打印 trace org.apache.ibatis.executor.statement.PreparedStatementHandler query

这是selectList 结果

image.png

这是selectObjs 结果

image.png

可以看到标红的时间差距

可以证明猜想是对的,就是说封装数据的过程最耗时间

结论

这里我虽然用的是mybatis-plus 框架,并不能代表全部的orm框架,但是呢原理都是差不多的,只要查询结果是对象,那就需要封装数据,就会去反射调用赋值

所以我们在开发中要注意这一点,如果只是查询一个字段,没必要用对象接收数据