温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

MySQL的count(*)怎么实现

发布时间:2021-12-04 14:36:40 来源:亿速云 阅读:232 作者:iii 栏目:大数据

这篇文章主要介绍“MySQL的count(*)怎么实现”,在日常操作中,相信很多人在MySQL的count(*)怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”MySQL的count(*)怎么实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

1. 背

自从大家对于MySQL数据库的稳定性有了更高的追求后,经常有小伙伴有这样的疑问,对于count(*)这样的操作,有没有正确的姿势,或者有没有可以优化的地方?

但答案比较残酷,如果已经使用了正确的索引,那么基本上没有可以优化的地方。一旦出现慢查询了,它就是慢查询了,要改,只能自己计数或者通过其他搜索平台来做。

今天,就一起来看看为什么会这样,并对大家日常会遇到的一些的困惑进行解答。

2. count(*)的实现方式

据说,MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候会直接返回这个数,效率很高。
而我们的mysql一般都是用Innodb的引擎,Innodb是怎么实现count操作的呢?
InnoDB 引擎就比较麻烦了,它执行 count(*) 的时候,需要把数据一行一行地从引擎里面读出来,然后累积计数。
所以,当我们的表里面的记录越来越多的时候,count(*)就会越来越慢。

当然,我们这里说的都是不带where条件的,如果带上where条件的话,MyISAM也是很慢的。

3.正确的打开方式

嗯,首先还是说,mysql上不太推荐用count(*)来做统计相关业务,尤其是表非常大的情况下。
那如果业务比较小,需要快速上马,那么,至少应该保证count(*)带上了科学的where条件,然后,这个表也已经建立了科学的索引。
1)如果count(*)带上的where条件,而且能够走覆盖索引,那还是可以偶尔走一走的。
2)如果count(*)带上的where条件,能够走索引,但是需要回表,那么这种就会比较危险,尤其是随着表规模的扩大,终究是一颗雷。
3)如果纯粹count(*),或者where条件没有任何索引,万万万不推荐!
那对于统计类的业务,推荐的几种做法:
1)带自增id的,可以用最大id来近似获取
2)自己计数

3)其他数据分析平台进行聚合

4. 能否用表统计信息代替count(*)

有同学在日常使用过程中,问能否使用 系统表的统计信息 来代替count。

答案是不行。这里的tableRows只是一个参考值。

这里的表统计信息,实际上是使用show table status获取的。  这个值是如何得到的呢?  我们需要了解下mysql的采样统计方法。
为什么要采样统计呢?  因为把整张表取出来一行行统计,虽然可以得到精确的结果,但是代价太高了,所以只能选择“采样统计”  (所以其实mysql自己也没有count(*)的好方法)。
采样统计的时候,InnoDB 默认会选择 N 个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。
而数据表是会持续更新的,索引统计信息也不会固定不变。  所以,当变更的数据行数超过 1/M 的时候,会自动触发重新做一次索引统计。

因此,这个采样估算得来的值,是很不准的。有多不准呢,官方文档说误差可能达到 40% 到 50%。

4.关于那些奇奇怪怪的count(?)

在看一些老代码查询的时候,我们经常会看到count(1),count(id),count(字段)等方式,那它们纠结孰优孰劣,到底有没有性能上的差异呢?

这里,我们先要弄清楚 count() 的语义。
count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加。  最后返回累计值。
1)count(主键id)
InnoDB 引擎会遍历整张表,把每一行的 id 值都取出来,返回给 server 层。  server 层拿到 id 后,判断是不可能为空的,就按行累加。
2)count(1)
InnoDB 引擎遍历整张表,但不取值。  server 层对于返回的每一行,放一个数字“1”进去,判断是不可能为空的,按行累加。
3) count(字段)
如果这个“字段”是定义为 not null 的话,一行行地从记录里面读出这个字段,判断不能为 null,按行累加;
如果这个“字段”定义允许为 null,那么执行的时候,判断到有可能是 null,还要把值取出来再判断一下,不是 null 才累加。
4)count(*)
并不会把全部字段取出来,而是专门做了优化,不取值。  count(*) 肯定不是 null,按行累加。
所以结论是:  按照效率排序的话,count(字段)<count(主键 id)<count(1)≈count(*),所以我建议,尽量使用 count(*)。

到此,关于“MySQL的count(*)怎么实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI