MySQL count() 真的慢吗

本文探讨了MySQL中InnoDB和MyISAM引擎在执行count(*)操作时的性能差异,以及为何InnoDB不保存表总行数的原因。InnoDB由于事务和MVCC的支持,无法像MyISAM那样快速获取总行数。同时,文章讨论了使用缓存(如Redis)和数据库(如计数表)来存储行数的优缺点,并比较了count()函数的不同实现方式的效率,建议使用count(*)作为优化策略。
摘要由CSDN通过智能技术生成

为什么我建议你使用 count(*)

MySQL 对 count(*) 的不同引擎实现

MyISAM 引擎把一个表里的总行数存在磁盘上, count(*) 直接返回这个数,会很快。

InnoDB 引擎执行 count(*) 会遍历索引树累积计数,当数据量大时,效率不高。

为什么 InnoDB 不像 MyISAM 将表总行数存起来?

因为 InnoDB 支持事务,根据MVCC原理,每个事务可见的行数是不确定的,因此需要逐条统计可见行。

另外show table status 命令虽然会统计总行数,但因为是采样统计,误差较大,在要求总行数精确的场景下不适用。

计数系统:缓存还是数据库

根据上述背景,我们要实现获取一张表的总行数,只能自己计数。

缓存存在的问题

  1. 丢失更新:虽然Redis读取内存很快,但是一旦异常重启,会造成数据丢失;
  2. 数据不一致:由于Redis不支持事务,无法保证多线程的执行序列。

数据库实现

如果用MySQL数据库的一张计数表存放行数是可以解决上述两个问题的。

  1. 首先InnoDB支持崩溃恢复,不回丢失数据
  2. 其次InnoDB支持事务MVCC,未提交事务的更新对其它事务不可见,不会看到脏数据。

count() 函数实现原理和性能对比

count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加。最后返回累计值。

所以,count(*)count(主键 id)count(1) 都表示返回满足条件的结果集的总行数;而 count(字段),则表示返回满足条件的数据行里面,参数“字段”不为 NULL 的总个数。

count(主键 id)

InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。

server 层拿到 id 后,判断是不可能为空的,就按行累加。

count(1)

InnoDB 引擎遍历整张表,但不取值

server 层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。

count(字段)

一行行地从记录里面读出这个字段,判断是否为 null,非空按行累加

count(*)

count(*) 是一个例外,因为 MySQL 专门对这个语句进行过优化。

它不会把所有字段取出来,实际上它不取值,只是按行累加

效率对比

按效率排序的话,count(字段) < count(主键 id) < count(1) ≈ count(*),所以可以使用 count(*)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值