1. 数据库结构

2. insert 测试

insert 的测试包括

1) 批量拼接values()插入

2) 有事务for循环插入

3) 无事务for循环插入

测试 SQL:

 <!-- 普通 insert -->
<insert id="insert"
parameterType="com.qunar.mybatistask.bean.Post"
keyProperty="id">
<![CDATA[ insert into post (
title,
content,
author,
status,
created
) values (
#{title},
#{content},
#{author},
#{status},
#{created}
) ]]>
</insert> <!-- 拼接values insert -->
<insert id="batchInsert"
parameterType="java.util.List">
<![CDATA[
insert into post (
title,
content,
author,
status,
created
) values
]]>
<foreach collection="list" item="post" separator=",">
(
#{post.title},
#{post.content},
#{post.author},
#{post.status},
#{post.created}
)
</foreach>
</insert>

测试代码:

service

    /**
* 批量拼接VALUES() insert
*
* @param postList
* @return
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int batchInsert(List<Post> postList) {
int singleNum = 1000;
int affectedRows = 0;
for (int i = 0; i < Math.ceil((double)(postList.size() / singleNum)); i++) {
affectedRows += sqlSession.insert("post.batchInsert", postList.subList(i * singleNum, (i + 1) * singleNum));
}
return affectedRows;
} /**
* 事务内循环insert
*
* @param postList
* @return
*/
@Override
@Transactional(propagation = Propagation.REQUIRED)
public int createList(List<Post> postList) {
int affectedRows = 0;
for (Post post : postList) {
affectedRows += sqlSession.insert("post.insert", post);
}
return affectedRows;
}

test case:

    /**
* 批量插入效率测试
*
* Method: batchInsert(List<Post> postList)
*
*/
@Test
public void testBatchInsert() throws Exception {
List<Post> postList = Lists.newArrayList();
for (int i = 0; i < 10000; i++) {
Post post = new Post();
post.setAuthor("test");
post.setContent("test");
post.setCreated(new Date());
post.setTitle("test");
post.setStatus(PostStatus.NORMAL);
postList.add(post);
} // 批量拼接SQL插入
long start = System.nanoTime();
int affectedRows = postService.batchInsert(postList);
double duration = System.nanoTime() - start;
System.out.format("batch: %.2f\n", duration / 1.0e9);
System.out.println("affected rows: " + affectedRows); // 事务内循环插入
start = System.nanoTime();
affectedRows = postService.createList(postList);
duration = System.nanoTime() - start;
System.out.format("transaction: %.2f\n", duration / 1.0e9);
System.out.println("affected rows: " + affectedRows); // 无事务直接循环插入
start = System.nanoTime();
affectedRows = 0;
for (Post post : postList)
affectedRows += postService.create(post);
duration = System.nanoTime() - start;
System.out.format("simple: %.2f\n", duration / 1.0e9);
System.out.println("affected rows: " + affectedRows);
}

结果

batch: 1.44
affected rows: 10000
transaction: 2.87
affected rows: 10000
simple: 77.57
affected rows: 10000

总结:

排行

1) 使用拼接的手段,这种插入其实就是batch,只不过这是手动batch

2) 使用事务循环插入,相对于无事务快很多的原因大概是数据库连接和事务开启的次数

3) 无事务循环插入, 我想应该没人这么写

2. 单表循环查询与拼接in查询测试

SQL

<select id="selectById" parameterType="int" resultType="com.qunar.mybatistask.bean.Post">
<![CDATA[ select
id,
title,
content,
author,
status,
created
from
post
where
id = #{id} ]]>
</select> <!-- 拼接where in条件查询 -->
<select id="selectIn" parameterType="java.util.List" resultType="com.qunar.mybatistask.bean.Post">
<![CDATA[
select
id,
title,
content,
author,
status,
created
from
post
where
id in
]]>
<foreach collection="list" item="id" open="(" close=")" separator=",">
#{id}
</foreach>
</select>

Service

    @Override
public Post selectById(int id) {
return sqlSession.selectOne("post.selectById", id);
} @Override
public List<Post> selectByIds(List<Integer> ids) {
List<Post> postList = Lists.newArrayList();
int singleNum = 1000;
int start;
int end;
for (int i = 0; i < Math.ceil(((double)ids.size() / (double)singleNum)); i++) {
start = i * singleNum;
end = (i + 1) * singleNum;
end = end > ids.size() ? ids.size() : end;
List<Post> result = sqlSession.selectList("post.selectIn", ids.subList(start, end));
postList.addAll(result);
}
return postList;
}

test case

    /**
* 使用IN查询效率测试
*
* @throws Exception
*/
@Test
public void testInSelect() throws Exception {
List<Integer> ids = Lists.newArrayList();
for (int i = 1; i < 10000; i++) {
ids.add(i);
} // in 查询
long start = System.nanoTime();
List<Post> list = postService.selectByIds(ids);
double duration = System.nanoTime() - start;
System.out.format("in select: %.2f\n", duration / 1.0e9);
System.out.println("list size: " + list.size()); // 循环查询
list = Lists.newArrayList();
start = System.nanoTime();
for (int id : ids)
list.add(postService.selectById(id));
duration = System.nanoTime() - start;
System.out.format("simple select: %.2f\n", duration / 1.0e9);
System.out.println("list size: " + list.size());
}

结果

in select: 0.55
list size: 9999
simple select: 6.24
list size: 9999

总结:

我想应该没人会用for循环去做查询吧

3. 多表联结查询, join, form 2个table, in, exists 比较

SQL

    <!-- 用于循环查询 -->
<select id="selectAll" resultType="com.qunar.mybatistask.bean.Comment">
<![CDATA[
select
cmt.id as id,
cmt.post_id as postId,
cmt.content as content
from
cmt
]]>
</select> <!-- join 查询 -->
<select id="selectJoin" resultType="com.qunar.mybatistask.bean.Comment">
<![CDATA[
select
cmt.id as id,
cmt.post_id as postId,
cmt.content as content
from
cmt
join
post
on
post.id = cmt.post_id
]]>
</select> <!-- from 2个table -->
<select id="selectTowTable" resultType="com.qunar.mybatistask.bean.Comment">
<![CDATA[
select
cmt.id as id,
cmt.post_id as postId,
cmt.content as content
from
cmt, post
where cmt.post_id = post.id
]]>
</select> <!-- in 联表查询 -->
<select id="selectIn" resultType="com.qunar.mybatistask.bean.Comment">
<![CDATA[
select
cmt.id as id,
cmt.post_id as postId,
cmt.content as content
from
cmt
where
cmt.post_id
in
(
select
post.id
from
post
)
]]>
</select> <!-- exists 联表查询 -->
<select id="selectExists" resultType="com.qunar.mybatistask.bean.Comment">
<![CDATA[
select
cmt.id as id,
cmt.post_id as postId,
cmt.content as content
from
cmt
where
exists
(
select
post.id
from
post
where
post.id = cmt.id
)
]]>
</select>

service

    @Override
public List<Comment> selectTwoTable() {
return sqlSession.selectList("comment.selectTowTable");
} @Override
public List<Comment> selectJoin() {
return sqlSession.selectList("comment.selectJoin");
} @Override
public List<Comment> selectIn() {
return sqlSession.selectList("comment.selectIn");
} @Override
public List<Comment> selectExists() {
return sqlSession.selectList("comment.selectExists");
} @Override
public List<Comment> selectAll() {
return sqlSession.selectList("comment.selectAll");
}

test case

    /**
* 测试JOIN查询效率
*
*/
@Test
public void testJoinSelect() {
// join 查询
long start = System.nanoTime();
List<Comment> list = commentService.selectJoin();
double duration = System.nanoTime() - start;
System.out.format("join select: %.2f\n", duration / 1.0e9);
System.out.println("list size: " + list.size()); // From 两个表查询
start = System.nanoTime();
list = commentService.selectTwoTable();
duration = System.nanoTime() - start;
System.out.format("2 table select: %.2f\n", duration / 1.0e9);
System.out.println("list size: " + list.size()); // in多表查询
start = System.nanoTime();
list = commentService.selectIn();
duration = System.nanoTime() - start;
System.out.format("in multi table select: %.2f\n", duration / 1.0e9);
System.out.println("list size: " + list.size()); // exists多表查询
start = System.nanoTime();
list = commentService.selectExists();
duration = System.nanoTime() - start;
System.out.format("exists multi table select: %.2f\n", duration / 1.0e9);
System.out.println("list size: " + list.size()); // 分次查询, 太慢了, 忽略这种方法的测试吧
// start = System.nanoTime();
// list = commentService.selectAll();
// for (Comment comment : list) {
// postService.selectById(comment.getPostId());
// }
// duration = System.nanoTime() - start;
// System.out.format("separate select: %.2f\n", duration / 1.0e9);
// System.out.println("list size: " + list.size());
}

结果

join select: 2.44
list size: 210000
2 table select: 2.26
list size: 210000
in multi table select: 2.03
list size: 210000
exists multi table select: 2.35
list size: 210000

总结:

21W条数据下效率都差不多,而且我们一般会使用limit去限制查询的条数,所以应该他们的效率差距应该很小,我通过观察explain发现实际上join和from 2个table的方式的查询的执行计划是一模一样的,而in和exists的执行计划也是一模一样的

这里的表结构相对简单,也基本能用上索引 post_id 和 post.id 这些primary, 具体更加复杂的情况也许会影响这几种查询方式的执行计划, 才会体现出他们直接的差距, 当然我也相信他们执行的效率很大程度上是决定于mysql的优化器的优化策略,而这个优化策略很难人为的去判断,所以也不好说

MyBatis+Spring SQL效率测试报告的更多相关文章

  1. Spring Boot 集成 MyBatis和 SQL Server实践

    概 述 Spring Boot工程集成 MyBatis来实现 MySQL访问的示例我们见过很多,而最近用到了微软的 SQL Server数据库,于是本文则给出一个完整的 Spring Boot + M ...

  2. 【spring boot】【mybatis】spring boot中mybatis打印sql语句

    spring boot中mybatis打印sql语句,怎么打印出来?[参考:https://www.cnblogs.com/sxdcgaq8080/p/9100178.html] 在applicati ...

  3. 【记录】spring/springboot 配置mybatis打印sql

    ======================springboot mybatis 打印sql========================================== 方式 一: ##### ...

  4. 集成框架 javaweb开发平台ssmy_m(生成代码) java struts2 mybatis spring maven jquery

    网页地址 http://blog.csdn.net/lpy3654321/article/details/31841573 项目设想,在项目开发中,我们的开发者大多数时间都在反复开发 相同的keywo ...

  5. MyBatis学习(一)、MyBatis简介与配置MyBatis+Spring+MySql

    一.MyBatis简介与配置MyBatis+Spring+MySql 1.1MyBatis简介 MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架.MyBatis 摒除了大部分的J ...

  6. MyBatis详解 与配置MyBatis+Spring+MySql

    MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架.MyBatis 摒除了大部分的JDBC代码.手工设置参数和结果集重获.MyBatis 只使用简单的XML 和注解来配置和映射基本 ...

  7. Maven+druid+MyBatis+Spring+Oracle+Dubbo开发环境搭建

    1.开发工具使用: MyEclipse或Eclipse,数据库使用Oracle.需要用到的软件有Zookeeper(注册中心),Tomcat(Web容器)和Maven(包管理). 2.初始环境配置: ...

  8. mybatis 打印sql 语句

    拦截器 package com.cares.asis.mybatis.interceptor; import java.text.DateFormat; import java.util.Date; ...

  9. 一、MyBatis简介与配置MyBatis+Spring+MySql

    //备注:该博客引自:http://limingnihao.iteye.com/blog/106076 1.1MyBatis简介 MyBatis 是一个可以自定义SQL.存储过程和高级映射的持久层框架 ...

随机推荐

  1. JavaScript中正则的使用(1)

    通过例子学习正则中的常见语法(1) $num javascript var a = 'javascript'; var b = a.replace(/(java)(script)/gi, '$2-$1 ...

  2. nginx卸载与安装

    1.卸载 在前面曾经安装过一次,这一次卸载再重新安装. 直接删除文件夹 2.更新软件源 3.依赖包安装 4.下载源码包并解压 5.增加用户组 6.安装 三个步骤 ./configure make ma ...

  3. linux下文件转码

    一.工具介绍 enca是一个很好用的文件转码工具,使用命令 sudo apt-get install enca 即可安装 二.基本用法 1.查看文件编码 $ enca filename 2.文件转码 ...

  4. CSS基础-DAY2

    CSS属性操作-文本 文本颜色 <head> <style> p{ /*color:#8B5742 ;色码表*/ color: RGBA(255,0,0,0.5); /*调色, ...

  5. Luogu 4492 [HAOI2018]苹果树 组合数

    https://www.luogu.org/problemnew/show/P4492 找每个编号的点的父边的贡献,组合数和阶乘就能算了. 我考场上怎么就是没想到呢. 调了好久好久好久好久调不出来,样 ...

  6. shellcode在栈溢出中的利用与优化

    0x00 前言 在<Windows Shellcode学习笔记——shellcode的提取与测试>中介绍了如何对shellcode作初步优化,动态获取Windows API地址并调用,并通 ...

  7. hdu 3338 最大流 ****

    题意: 黑格子右上代表该行的和,左下代表该列下的和 链接:点我 这题可以用网络流做.以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变.求满足的最大流.由于 ...

  8. 【洛谷】4917:天守阁的地板【欧拉函数的应用】【lcm与gcd】【同除根号优化】

    P4917 天守阁的地板 题目背景 在下克上异变中,博丽灵梦为了找到异变的源头,一路打到了天守阁 异变主谋鬼人正邪为了迎击,将天守阁反复颠倒过来,而年久失修的天守阁也因此掉下了很多块地板 异变结束后, ...

  9. Dijkstra_Liu博客100篇祭

    创建博客,有两年三个月了.今天,写了100篇随笔了,又正值我的15岁生日,还是值得纪念一下. 两年过去了,我从学习:队列.栈.模拟.背包慢慢地变成了:Tarjan.线段树.树剖. 我也从一个初一的天真 ...

  10. HTML5 UI 控件Mobiscroll的使用(年月日三级联动)

    概述: 遇到制作一个html5界面,需要选择年月日,其实这个功能很常用.一般我们都是网上找,之前也没有收藏一个自己常用的,今天发现一个不错的库.特此记录一下使用过程,以便以后遇到了方面查阅. 1.官方 ...