小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
前言
项目运行中经常会遇到db查询超时,这时候大家往往都会想到去优化sql,但是今天我想说的一个观点是查询超时可能不是sql语句问题也可能是orm框架问题
环境
orm:mybatis-plusdb: 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 结果
这是selectObjs 结果
可以看到标红的时间差距
可以证明猜想是对的,就是说封装数据的过程最耗时间
结论
这里我虽然用的是mybatis-plus 框架,并不能代表全部的orm框架,但是呢原理都是差不多的,只要查询结果是对象,那就需要封装数据,就会去反射调用赋值
所以我们在开发中要注意这一点,如果只是查询一个字段,没必要用对象接收数据