统计一张表的总数量,是我们开发中常有的业务需求,通常情况下,我们都是使用 select count(*) from t SQL 语句来完成。随着业务数据的增加,你会发现这条语句执行的速度越来越慢,为什么它会变慢呢?

为什么会变慢?想要得到答案就需要知道 MySQL 是如何统计总数量的,先说一个前提吧,count(*) 的具体实现是由存储引擎实现的,也就是说不同的存储引擎实现的方式不一样。标题:为什么select count( * ) from t,在 InnoDB 引擎中比 MyISAM 慢?也是高频面试题。

InnoDB和MyISAM 是我们常用的 MySQL 存储引擎,所以主要对比一下 count(*) 在 InnoDB 和 MyISAM 中的实现:

  • 「在 MyISAM 存储引擎中,把表的总行数存储在磁盘上,当执行 select count(*) from t 时,直接返回总数据」

  • 「在 InnoDB 存储引擎中,跟 MyISAM 不一样,没有将总行数存储在磁盘上,当执行 select count(*) from t 时,会先把数据读出来,一行一行的累加,最后返回总数量」

知道了 InnoDB 和 MyISAM 引擎 count(*) 实现之后,为什么select count(*) from t,在 InnoDB 引擎中比 MyISAM 慢?应该有答案了吧,但是这个结论需要有一个前提,就是统计 SQL 不带过滤条件。如果 统计数量 SQL 语句为:select count(*) from t where x = 23,那么在 MyISAM 中就不一定比 InnoDB 快了。

「InnoDB 中 count(*) 语句是在执行的时候,全表扫描统计总数量,所以当数据越来越大时,语句就越来越耗时了」,为什么 InnoDB 引擎不像 MyISAM 引擎一样,将总行数存储到磁盘上?这跟 InnoDB 的事务特性有关,由于多版本并发控制(MVCC)的原因,InnoDB 表“应该返回多少行”也是不确定的。

不妨用一个例子来说明一下,假设现在 t 表中有 10000 条数据,现在有三个用户同时访问的会话:

  • 会话 A 先启动事务并查询一次表的总行数。

  • 会话 B 启动事务,插入一行后记录后,查询表的总行数。

  • 会话 C 先启动一个单独的语句,插入一行记录后,查询表的总行数。

会话执行流程图

假设从上到下是按照时间顺序执行的,同一行语句是在同一时刻执行的。可以看出在最后时刻,三个会话返回的总行数不一样。

出现不一样的结果跟 InnoDB 存储引擎有关系,「在默认隔离级别可重复读的情况下,通过多版本并发控制(MVCC)来实现,每一行记录都需要判断自己是否对这个会话可见,因此在统计总数量时,InnoDB 只好把数据一行一行的读取出来判断,只有当前会话可见的才纳入统计中」。所以同一时刻不同会话查询到的数量就不一样。

InnoDB 引擎在 count(*)语句上也做了优化,我们知道,在 InnoDB 存储引擎中是以索引组织表的方式存储数据,主键索引树上叶子节点存放在所有的数据,而普通索引树的叶子节点是主键值,所以普通索引树会比主键索引树小很多,但是数量是一样的,也就是说遍历主键索引树和普通索引树得到的结果都是一样的。MySQL 就利用了这一特性,在 InnoDB 中执行 select count(*) from t语句时,MySQL 优化器会找到最小的那棵索引树来遍历,这样可能就可以减少加载次数,在一定程度上提升了 count(*)的执行效率。

最后,再附上我历时三个月总结的 Java 面试 + Java 后端技术学习指南,这是本人这几年及春招的总结,目前,已经拿到了大厂offer,拿去不谢!

下载方式

1. 首先扫描下方二维码

2. 后台回复「Java面试」即可获取

为什么 select count(*) from t,在 InnoDB 引擎中比 MyISAM 慢?相关推荐

  1. 聊一聊 InnoDB 引擎中的索引类型

    索引对数据库有多重要,我想大家都已经知道了吧,关于索引可能大家会对它多少有一些误解,首先索引是一种数据结构,并且索引不是越多越好.合理的索引可以提高存储引擎对数据的查询效率. 形象一点来说呢,索引跟书 ...

  2. MySQL存储引擎中的MyISAM和InnoDB区别详解

    MyISAM是MySQL的默认数据库引擎(5.5版之前),由早期的ISAM(Indexed Sequential Access Method:有索引的顺序访问方法)所改良.虽然性能极佳,但却有一个缺点 ...

  3. (读书笔记)关于InnoDB引擎中的一致性锁定读

    我们上篇主要讲到,在默认配置下,即事务的隔离级别为 REPEATABLE READ模式下,InnoDB 存储引擎的select操作使用一致性非锁定读 但是在某些情况下,用户需要显式地对数据库读取操作进 ...

  4. Innodb引擎中B+树一般有几层?能容纳多少数据量?

    参考: 面试题:InnoDB中B+树有几层?_Running-Waiting的博客-CSDN博客_b+树有几层 mysql单表最多两千万条数据? 先说结论:一般B+树高大约为1~3层(通过主键索引查询 ...

  5. mysql innodb count_MySQL下INNODB引擎的SELECT COUNT(*)性能优化及思考

    正 文: MySQL下INNODB引擎的SELECT COUNT(*)性能优化及思考 最近有项目有高并发需求,服务器采用负载均衡,数据库采用阿里云的RDS MYSQL,16核64G内存,连接数:160 ...

  6. 你知道select count(*)底层究竟干了啥么?

    作者:贾春生 https://blog.didiyun.com/index.php/2019/01/08/mysql-count/ "SELECT COUNT( * ) FROM T&quo ...

  7. SELECT COUNT(*) 底层究竟干了啥么?

    "SELECT COUNT( * ) FROM TABLE" 是个再常见不过的 SQL 需求了.在 MySQL 的使用规范中,我们一般使用事务引擎 InnoDB 作为(一般业务)表 ...

  8. select count(*)底层究竟干了啥么?

    转载自  select count(*)底层究竟干了啥么? "SELECT COUNT( * ) FROM t" 是个再常见不过的 SQL 需求了.在 MySQL 的使用规范中,我 ...

  9. select count(*) from返回值_MySQL 优化:count(1)真的比count(*)快吗

    在实际项目开发中一定会有统计记录数的需求,比如统计用户数,像一些电商系统后台首页会统计订单量.上架商品数量等等,涉及到统计就离不开聚合函数 count() ,开发中常用写法如下: select cou ...

最新文章

  1. 利用Java生成静态HMTL页面的方法收集
  2. CONTINUE...? ZOJ - 4033
  3. [Godot] v4.0.alpha1 GDScript 实现第三人称控制器
  4. 算法思想——贪心(详细举例理解~)
  5. 事业编,还有前途可谈么?
  6. shell 执行qt生成文件_QT-窗口打印debug信息,本地日志保存,以及执行shell脚本并且把信息打印在窗口...
  7. IE8的模式修改优化Windows7
  8. matlab小波分析
  9. 根据后缀名/扩展名获取content-type/Mime类型
  10. JAVA怎么打开pkg_PKG文件在电脑上怎么打开!(普通PC)
  11. dCas9稳转细胞系概述
  12. VTN线下体验店 汇聚全球高端品牌 打造非凡购物体验
  13. vue-awsome-swiper安装和css引入问题
  14. 基于C语言实现的汽车牌照的快速查询
  15. 4.19 C语言练习(已有一个已正序排好的9个元素的数组,今输入一个数要求按原来排序的规律将它插入数组中)
  16. python新手小练习(三)企业奖金提成
  17. flask自定义过滤器,flash,form表单
  18. 一个设想:什么是真正的云,及利用树莓派和cloudwall打造你的真正云中心
  19. Python编程:使用os.urandom生成Flask的秘钥SECRET_KEY
  20. 网络营销好学吗?自学和培训该怎么选?

热门文章

  1. 标记【新公司】!!!!!!!!!!
  2. 802.11 帧格式及类型
  3. 如何用jlink+jflash烧写stm32f103CB的option bytes 和程序
  4. C++ Primer 5th笔记(chap 18 大型程序工具)捕获异常
  5. FileCoin (1) 初步介绍
  6. C++ Primer 5th笔记(10)chapter10 泛型算法 :谓词
  7. python字节码大全
  8. 二叉搜索树简介和部分题目
  9. 【Flask】url_for函数
  10. LPCTSTR 与 int 的互相转换