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

文章探讨了MySQL中InnoDB和MyISAM存储引擎在执行count(*)查询时的性能差异。InnoDB由于其事务处理和MVCC机制,在没有过滤条件的情况下,count(*)操作需要全表扫描,导致速度较MyISAM慢,后者直接存储表的总行数。然而,InnoDB通过选择最小索引树来优化查询,提高效率。在有过滤条件的查询中,两者的性能比较则取决于具体条件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

统计一张表的总数量,是我们开发中常有的业务需求,通常情况下,我们都是使用 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(*)的执行效率。

### MyISAMInnoDB 存储引擎的主要区别 #### 性能与应用场景 MyISAM 更适用于读密集型的操作环境,尤其当应用程序主要涉及查询操作而非频繁写入时。相比之下,InnoDB 则更适合于高并发场景以及需要事务支持的情况[^1]。如果业务逻辑中存在大量的增删改操作或者对外键约束有需求,则应优先考虑使用 InnoDB。 #### 查询效率对比 从查询效率来看,在纯 SELECT 操作下,通常情况下 MyISAM 表的表现优于 InnoDB;然而在 INSERT 或 UPDATE 场景里则是后者占据优势[^2]。因此可以根据具体的工作负载特性来决定采用哪种存储引擎更为合适。 #### 数据完整性保障机制 关于数据安全性和一致性方面,两者之间也存在显著差异——InnoDB 提供了完整的 ACID 遵循能力并通过引入 MVCC (Multi-Version Concurrency Control) 来管理多个会话间的交互过程,同时还允许定义外键关系以维护参照完整性[^4]。与此相反的是,尽管 MyISAM 能够快速完成某些特定任务比如全文检索等功能,但它缺乏内置的事物处理能力和跨表关联控制手段[^3]。 #### 特殊功能支持情况 另外值得注意的一点在于特殊索引形式上的差别:虽然二者均支持 B+Tree 类型的标准次序访问路径构建方式,但是只有 InnoDBMySQL 5.6 开始才正式加入了对 FULLTEXT 文本匹配结构的支持,并且随着版本迭代逐步完善了针对地理位置信息建模所需的相应工具集[^4]。与此同时,由于其实现原理的不同之处决定了它们各自具备独特的优势项目列表如下所示: | 功能项 | **MyISAM** | **InnoDB** | |----------------|------------------|--------------------| | 备份/时间点恢复 | 支持 | 支持 | | 压缩数据 | 只读模式下的部分支持 | 完整支持 | | 加密数据 | 使用外部插件实现 | 内置支持 | | 聚合索引 | 不支持 | 支持 | | 外键支持 | 缺乏原生支持 | 强大支持 | 最后还需提及一点有关元数据统计更新频率的问题:每当发生任何修改动作之后都会触发重新计算相关指标的动作发生在 Innodb 上面;而对于那些基于固定计数值维持策略设计出来的 Myisam 文件而言则无需如此繁琐的过程就能即时获取到总数目等基本信息[^5]。 ```sql SELECT COUNT(*) FROM my_table; ``` 以上就是围绕这两个主流 mysql 存储引擎展开讨论所得出的一些核心结论概述。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖天才小朱(怀玉)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值