1. 数据库结构

2. insert 测试

insert 的测试包括

1) 批量拼接values()插入

2) 有事务for循环插入

3) 无事务for循环插入

测试 SQL:

  1. <!-- 普通 insert -->
  2. <insert id="insert"
  3. parameterType="com.qunar.mybatistask.bean.Post"
  4. keyProperty="id">
  5. <![CDATA[
  6.  
  7. insert into post (
  8. title,
  9. content,
  10. author,
  11. status,
  12. created
  13. ) values (
  14. #{title},
  15. #{content},
  16. #{author},
  17. #{status},
  18. #{created}
  19. )
  20.  
  21. ]]>
  22. </insert>
  23.  
  24. <!-- 拼接values insert -->
  25. <insert id="batchInsert"
  26. parameterType="java.util.List">
  27. <![CDATA[
  28. insert into post (
  29. title,
  30. content,
  31. author,
  32. status,
  33. created
  34. ) values
  35. ]]>
  36. <foreach collection="list" item="post" separator=",">
  37. (
  38. #{post.title},
  39. #{post.content},
  40. #{post.author},
  41. #{post.status},
  42. #{post.created}
  43. )
  44. </foreach>
  45. </insert>

测试代码:

service

  1. /**
  2. * 批量拼接VALUES() insert
  3. *
  4. * @param postList
  5. * @return
  6. */
  7. @Override
  8. @Transactional(propagation = Propagation.REQUIRED)
  9. public int batchInsert(List<Post> postList) {
  10. int singleNum = 1000;
  11. int affectedRows = 0;
  12. for (int i = 0; i < Math.ceil((double)(postList.size() / singleNum)); i++) {
  13. affectedRows += sqlSession.insert("post.batchInsert", postList.subList(i * singleNum, (i + 1) * singleNum));
  14. }
  15. return affectedRows;
  16. }
  17.  
  18. /**
  19. * 事务内循环insert
  20. *
  21. * @param postList
  22. * @return
  23. */
  24. @Override
  25. @Transactional(propagation = Propagation.REQUIRED)
  26. public int createList(List<Post> postList) {
  27. int affectedRows = 0;
  28. for (Post post : postList) {
  29. affectedRows += sqlSession.insert("post.insert", post);
  30. }
  31. return affectedRows;
  32. }

test case:

  1. /**
  2. * 批量插入效率测试
  3. *
  4. * Method: batchInsert(List<Post> postList)
  5. *
  6. */
  7. @Test
  8. public void testBatchInsert() throws Exception {
  9. List<Post> postList = Lists.newArrayList();
  10. for (int i = 0; i < 10000; i++) {
  11. Post post = new Post();
  12. post.setAuthor("test");
  13. post.setContent("test");
  14. post.setCreated(new Date());
  15. post.setTitle("test");
  16. post.setStatus(PostStatus.NORMAL);
  17. postList.add(post);
  18. }
  19.  
  20. // 批量拼接SQL插入
  21. long start = System.nanoTime();
  22. int affectedRows = postService.batchInsert(postList);
  23. double duration = System.nanoTime() - start;
  24. System.out.format("batch: %.2f\n", duration / 1.0e9);
  25. System.out.println("affected rows: " + affectedRows);
  26.  
  27. // 事务内循环插入
  28. start = System.nanoTime();
  29. affectedRows = postService.createList(postList);
  30. duration = System.nanoTime() - start;
  31. System.out.format("transaction: %.2f\n", duration / 1.0e9);
  32. System.out.println("affected rows: " + affectedRows);
  33.  
  34. // 无事务直接循环插入
  35. start = System.nanoTime();
  36. affectedRows = 0;
  37. for (Post post : postList)
  38. affectedRows += postService.create(post);
  39. duration = System.nanoTime() - start;
  40. System.out.format("simple: %.2f\n", duration / 1.0e9);
  41. System.out.println("affected rows: " + affectedRows);
  42. }

结果

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

  1. <select id="selectById" parameterType="int" resultType="com.qunar.mybatistask.bean.Post">
  2. <![CDATA[
  3.  
  4. select
  5. id,
  6. title,
  7. content,
  8. author,
  9. status,
  10. created
  11. from
  12. post
  13. where
  14. id = #{id}
  15.  
  16. ]]>
  17. </select>
  18.  
  19. <!-- 拼接where in条件查询 -->
  20. <select id="selectIn" parameterType="java.util.List" resultType="com.qunar.mybatistask.bean.Post">
  21. <![CDATA[
  22. select
  23. id,
  24. title,
  25. content,
  26. author,
  27. status,
  28. created
  29. from
  30. post
  31. where
  32. id in
  33. ]]>
  34. <foreach collection="list" item="id" open="(" close=")" separator=",">
  35. #{id}
  36. </foreach>
  37. </select>

Service

  1. @Override
  2. public Post selectById(int id) {
  3. return sqlSession.selectOne("post.selectById", id);
  4. }
  5.  
  6. @Override
  7. public List<Post> selectByIds(List<Integer> ids) {
  8. List<Post> postList = Lists.newArrayList();
  9. int singleNum = 1000;
  10. int start;
  11. int end;
  12. for (int i = 0; i < Math.ceil(((double)ids.size() / (double)singleNum)); i++) {
  13. start = i * singleNum;
  14. end = (i + 1) * singleNum;
  15. end = end > ids.size() ? ids.size() : end;
  16. List<Post> result = sqlSession.selectList("post.selectIn", ids.subList(start, end));
  17. postList.addAll(result);
  18. }
  19. return postList;
  20. }

test case

  1. /**
  2. * 使用IN查询效率测试
  3. *
  4. * @throws Exception
  5. */
  6. @Test
  7. public void testInSelect() throws Exception {
  8. List<Integer> ids = Lists.newArrayList();
  9. for (int i = 1; i < 10000; i++) {
  10. ids.add(i);
  11. }
  12.  
  13. // in 查询
  14. long start = System.nanoTime();
  15. List<Post> list = postService.selectByIds(ids);
  16. double duration = System.nanoTime() - start;
  17. System.out.format("in select: %.2f\n", duration / 1.0e9);
  18. System.out.println("list size: " + list.size());
  19.  
  20. // 循环查询
  21. list = Lists.newArrayList();
  22. start = System.nanoTime();
  23. for (int id : ids)
  24. list.add(postService.selectById(id));
  25. duration = System.nanoTime() - start;
  26. System.out.format("simple select: %.2f\n", duration / 1.0e9);
  27. System.out.println("list size: " + list.size());
  28. }

结果

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

总结:

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

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

SQL

  1. <!-- 用于循环查询 -->
  2. <select id="selectAll" resultType="com.qunar.mybatistask.bean.Comment">
  3. <![CDATA[
  4. select
  5. cmt.id as id,
  6. cmt.post_id as postId,
  7. cmt.content as content
  8. from
  9. cmt
  10. ]]>
  11. </select>
  12.  
  13. <!-- join 查询 -->
  14. <select id="selectJoin" resultType="com.qunar.mybatistask.bean.Comment">
  15. <![CDATA[
  16. select
  17. cmt.id as id,
  18. cmt.post_id as postId,
  19. cmt.content as content
  20. from
  21. cmt
  22. join
  23. post
  24. on
  25. post.id = cmt.post_id
  26. ]]>
  27. </select>
  28.  
  29. <!-- from 2个table -->
  30. <select id="selectTowTable" resultType="com.qunar.mybatistask.bean.Comment">
  31. <![CDATA[
  32. select
  33. cmt.id as id,
  34. cmt.post_id as postId,
  35. cmt.content as content
  36. from
  37. cmt, post
  38. where cmt.post_id = post.id
  39. ]]>
  40. </select>
  41.  
  42. <!-- in 联表查询 -->
  43. <select id="selectIn" resultType="com.qunar.mybatistask.bean.Comment">
  44. <![CDATA[
  45. select
  46. cmt.id as id,
  47. cmt.post_id as postId,
  48. cmt.content as content
  49. from
  50. cmt
  51. where
  52. cmt.post_id
  53. in
  54. (
  55. select
  56. post.id
  57. from
  58. post
  59. )
  60. ]]>
  61. </select>
  62.  
  63. <!-- exists 联表查询 -->
  64. <select id="selectExists" resultType="com.qunar.mybatistask.bean.Comment">
  65. <![CDATA[
  66. select
  67. cmt.id as id,
  68. cmt.post_id as postId,
  69. cmt.content as content
  70. from
  71. cmt
  72. where
  73. exists
  74. (
  75. select
  76. post.id
  77. from
  78. post
  79. where
  80. post.id = cmt.id
  81. )
  82. ]]>
  83. </select>

service

  1. @Override
  2. public List<Comment> selectTwoTable() {
  3. return sqlSession.selectList("comment.selectTowTable");
  4. }
  5.  
  6. @Override
  7. public List<Comment> selectJoin() {
  8. return sqlSession.selectList("comment.selectJoin");
  9. }
  10.  
  11. @Override
  12. public List<Comment> selectIn() {
  13. return sqlSession.selectList("comment.selectIn");
  14. }
  15.  
  16. @Override
  17. public List<Comment> selectExists() {
  18. return sqlSession.selectList("comment.selectExists");
  19. }
  20.  
  21. @Override
  22. public List<Comment> selectAll() {
  23. return sqlSession.selectList("comment.selectAll");
  24. }

test case

  1. /**
  2. * 测试JOIN查询效率
  3. *
  4. */
  5. @Test
  6. public void testJoinSelect() {
  7. // join 查询
  8. long start = System.nanoTime();
  9. List<Comment> list = commentService.selectJoin();
  10. double duration = System.nanoTime() - start;
  11. System.out.format("join select: %.2f\n", duration / 1.0e9);
  12. System.out.println("list size: " + list.size());
  13.  
  14. // From 两个表查询
  15. start = System.nanoTime();
  16. list = commentService.selectTwoTable();
  17. duration = System.nanoTime() - start;
  18. System.out.format("2 table select: %.2f\n", duration / 1.0e9);
  19. System.out.println("list size: " + list.size());
  20.  
  21. // in多表查询
  22. start = System.nanoTime();
  23. list = commentService.selectIn();
  24. duration = System.nanoTime() - start;
  25. System.out.format("in multi table select: %.2f\n", duration / 1.0e9);
  26. System.out.println("list size: " + list.size());
  27.  
  28. // exists多表查询
  29. start = System.nanoTime();
  30. list = commentService.selectExists();
  31. duration = System.nanoTime() - start;
  32. System.out.format("exists multi table select: %.2f\n", duration / 1.0e9);
  33. System.out.println("list size: " + list.size());
  34.  
  35. // 分次查询, 太慢了, 忽略这种方法的测试吧
  36. // start = System.nanoTime();
  37. // list = commentService.selectAll();
  38. // for (Comment comment : list) {
  39. // postService.selectById(comment.getPostId());
  40. // }
  41. // duration = System.nanoTime() - start;
  42. // System.out.format("separate select: %.2f\n", duration / 1.0e9);
  43. // System.out.println("list size: " + list.size());
  44. }

结果

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. hdoj2159 FATE(完全背包)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2159 思路 每种怪都有无限个,所以使用完全背包来解决.这题比普通完全背包多了一个条件,就是杀怪的个数不 ...

  2. JS日期、时间 格式化转换方法

    Date.prototype.format = function(fmt) { var o = { "M+" : this.getMonth()+1, //月份 "d+& ...

  3. ACM训练计划建议(转)

    ACM训练计划建议 From:freecode#  Date:2015/5/20 前言: 老师要我们整理一份训练计划给下一届的学弟学妹们,整理出来了,费了不少笔墨,就也将它放到博客园上供大家参考. 菜 ...

  4. 【工具】获取pojo类属性,并写入表格

    1.添加依赖 <!-- https://mvnrepository.com/artifact/org.apache.poi/poi --> <dependency> <g ...

  5. React Native踩坑之The SDK directory 'xxxxx' does not exist

    相信和我一样,自己摸索配置环境的过程中,第一次配,很可能就遇到了这个比较简单地错误,没有配置sdk环境 解决办法 在电脑,系统环境变量中,添加一个sdk的环境变量 uploading-image-95 ...

  6. 五、django rest_framework源码之版本控制剖析

    1 绪论 Djangorest_framework的版本控制允许用户更改不同客户端之间的行为,且提供了许多不同的版本控制方案.版本控制由传入的客户端请求确定,可以基于请求URL,也可以基于请求标头. ...

  7. 数据库中drop、delete与truncate的区别

    数据库中drop.delete与truncate的区别 drop直接删掉表: truncate删除表中数据,再插入时自增长id又从1开始 :delete删除表中数据,可以加where字句. (1) D ...

  8. luoguP4555 [国家集训队]最长双回文串 manacher算法

    不算很难的一道题吧.... 很容易想到枚举断点,之后需要处理出以$i$为开头的最长回文串的长度和以$i$为结尾的最长回文串的长度 分别记为$L[i]$和$R[i]$ 由于求$R[i]$相当于把$L[i ...

  9. Needed Learning(Updating)

    决定把掌握不熟练或是模型见的少的知识点在这里列一列 希望能在自己AFO前成功get技能点吧…… 优先级:动态规划-分治-字符串-图论-数据结构-数学-计算几何-其它 动态规划 1.四边形不等式优化 2 ...

  10. 【推导】【贪心】Codeforces Round #472 (rated, Div. 2, based on VK Cup 2018 Round 2) D. Riverside Curio

    题意:海平面每天高度会变化,一个人会在每天海平面的位置刻下一道痕迹(如果当前位置没有已经刻划过的痕迹),并且记录下当天比海平面高的痕迹有多少条,记为a[i].让你最小化每天比海平面低的痕迹条数之和. ...