当前位置: 首页 > news >正文

告诉你为什么为什么 SELECT COUNT(*) FROM table 在 InnoDB 引擎中比 MyISAM引擎中的速度慢

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

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

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

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

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

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

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

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

会话执行流程表

会话A会话B会话C
begin;
select count(*) from table
insert into table (插入一行)
begin;
insert into table(插入一行)
select count(*) from table;(返回10000)select count(*) from table;(返回10002)select count(*) from table;(返回10001)

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

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

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

http://www.lryc.cn/news/10482.html

相关文章:

  • Redis 命令和Redis key键
  • 如何入侵服务器
  • 在Windows10上安装虚拟机---VMware 17 Pro下载与安装
  • 生命周期函数、组件
  • 蓝桥杯 stm32 PWM 测量频率
  • Docker CPU 资源控制
  • 小红书数据平台:笔记爆文率提升的三大秘诀公式!
  • Spring MVC 之Tomcat启动流程
  • 大疆车载更新产品矩阵,覆盖从主动安全到城区领航的全场景
  • 总结Anisble中的任务执行控制并练习
  • PMP好考吗,有多大的价值?
  • http常用状态码(204,304, 404, 504,502)含义
  • 记录锁,间隙锁,插入意向锁,临键锁兼容关系
  • map相关接口(map接口、HashMap、LinkedHashMap、TreeMap)
  • 抽象工厂模式(Abstract Factory Pattern)
  • Linux驱动学习笔记
  • tarfile — 访问 Tar 压缩文件
  • C++14深度探索之C++基础-共享指针与弱指针使用
  • 【React全家桶】reac组件通信
  • 2023,再转行去做软件测试还有前途吗?
  • Java程序API数据接口
  • 剑指offer 7 数组中和为0的三个数
  • DockerFile
  • Vue-Router 介绍及路由原理分析
  • git代码提交后jenkins构建和自动部署
  • 2023面试题目总结
  • Vue常用指令及声明周期
  • MariaDB 成功敲钟上市 | 它与 Navciat 缘起 10 年前
  • LESS模型与随机森林
  • 如何利用Power Virtual Agents机器人实现成绩查询服务