有一个问题是这样的统计数据总数用count(*)、count(主键ID)、count(字段)、count(1)那个效率高。

先说结论,不用那么花里胡哨遇到统计总数全部使用count(*).

但是有很多小伙伴就会问为什么呢?本期文章就解决大家的为什么。

文章目录

  • 系列文章
  • 一、不同存储引擎的做法
  • 二、MySQL对count(*)做了什么优化
  • 三、不同count的用法
  • 五、总结

系列文章

五分钟,让你明白MySQL是怎么选择索引《死磕MySQL系列 六》

字符串可以这样加索引,你知吗?《死磕MySQL系列 七》

无法复现的“慢”SQL《死磕MySQL系列 八》

什么?还在用delete删除数据《死磕MySQL系列 九》

一、不同存储引擎的做法

你需要知道的是在不同的存储引擎下,MySQL对于使用count(*)返回结果的流程是不一样的。

在Myisam中,每张表的总行数都会存储在磁盘上,因此执行count(*)时,是直接从磁盘拿到这个值返回,效率是非常高的。但你也要知道如果加了条件的统计总数返回也不会那么快的。

在Innodb引擎中,执行count(*),需要把数据一行一行的读出来,然后再统计总数返回。

问题:为什么Innodb不跟Myisam一样把表总数存起来呢?

这个问题就需要追溯的我们之前的MVCC文章,就是因为要实现多版本并发控制,才会导致Innodb不能直接存储表总数。

因为每个事务获取到的一致性视图都是不一样的,所以返回的数据总数也是不一致的。

如果你无法理解,再回到MVCC文章好好看看,意思就跟不同事务看到的数据不一致一回事。

实战案例

假设这三个用户是并行的,你会看到三个用户看到最终的数据总数都不一致。

每个用户会根据read view存储的数据来判断那些数据是自己可以看见的,那些是看不见的。

read view

当执行SQL语句查询时会产生一致性视图,也就是read-view,它是由查询的那一时间所有未提交事务ID组成的数组,和已经创建的最大事务ID组成的。

在这个数组中最小的事务ID被称之为min_id,最大事务ID被称之为max_id,查询的数据结果要根据read-view做对比从而得到快照结果。

于是就产生了以下的对比规则,这个规则就是使用当前的记录的trx_id跟read-view进行对比,对比规则如下。

如果落在trx_id<min_id,表示此版本是已经提交的事务生成的,由于事务已经提交所以数据是可见的

如果落在trx_id>max_id,表示此版本是由将来启动的事务生成的,是肯定不可见的

若在min_id<=trx_id<=max_id时

  • 如果row的trx_id在数组中,表示此版本是由还没提交的事务生成的,不可见,但是当前自己的事务是可见的
  • 如果row的trx_id不在数组中,表明是提交的事务生成了该版本,可见

二、MySQL对count(*)做了什么优化

先来看两个索引结构,一个是主键索引、另一个是普通索引。

现在你应该知道了,主键索引的叶子节点存储的是整行数据,而普通索引叶子节点存储的是主键值。

得出结论就是普通索引的比主键索引会小很多。

所以,MySQL对于count(*)这样的操作,不管遍历那个索引树得到的结果在逻辑上都一样。

因此,优化器会找到最小的那棵树来遍历,在保证正确的逻辑前提下,尽量减少扫描数据量,是数据库系统设计的通用法则之一。

问题:为什么存储的有数据怎么不用?

这个图的数据怎么得到的,我想你应该知道了,没错,就是执行show table status \G;得来的。

那为什么innodb存储引擎不直接使用Rows这个值呢?

还记不记得在第六期文章中,五分钟,让你明白MySQL是怎么选择索引《死磕MySQL系列 六》

先不要返回去看这篇文章,看下上文图中最后查到的数据总条数是多少。

你会发现这两个统计的数据是不一致的,因此这个值肯定是不可以用的。

具体原因

因为Rows这个值跟索引基数Cardinality一样,都是通过采样统计的。

采样规则

首先,会选出N个数据页,然后统计每个数据页上不同的值,最后得到一个平均值。再用这个平均值乘索引的数据页总数得到的就是索引基数。

并且这个索引基数也不是一成不变的,会随着数据持续增删改,当变更的数据超过1/M时才会触发,M值是根据MySQL参数innodb_stats_persistent得到的,设置为on是10,off是16。

在MySQL8.0这个默认值为on,也就是说当这张表的数据变更超过总数据的1/10就会重新触发采样统计。

三、不同count的用法

以下所有的结论都基于MySQL的Innodb存储引擎。

count(主键ID)

innodb引擎会遍历整张表,把每一行的ID值都那出来,然后返回给server层,server层拿到ID后,判断不可能为空,进行累加。

count(1)

同样遍历整张表,但不取值,server层对返回的每一行,放一个数字1进去,判断是不可能为空的,按行累加。

count(字段)

分为两种情况,字段定义为not null和null

  • 为not null时:逐行从记录里面读出这个字段,判断不能为null,累加
  • 为 null时:执行时,判断到有可能是null,还要把值取出来再判断一下,不是null才累加。

count(*)

这个哥们就厉害了,不是带了*就把所有值取出来,而是MySQL做了专门的优化,count ( * )肯定不是null,按行累加。

结论

按照效率的话,字段 < 主键ID < 1 ~ ,最好都使用count(),别花里胡哨的。

五、总结

本期文章就一句话,统计总数就用count(*),别花里胡哨的

坚持学习、坚持写作、坚持分享是咔咔从业以来所秉持的信念。愿文章在偌大的互联网上能给你带来一点帮助,我是咔咔,下期见。

MySQL统计总数就用count,别花里胡哨的《死磕MySQL系列 十》相关推荐

  1. 重重封锁,让你一条数据都拿不到《死磕MySQL系列 十三》

    在开发中有遇到很简单的SQL却执行的非常慢,甚至只查询一行数据. 咔咔遇到的只有两种情况,一种是MySQL服务器CPU占用率很高,所有的SQL都执行的很慢直到超时,程序也直接502,另一种情况是行锁造 ...

  2. 死磕数据库系列(三十三):MySQL 性能分析与相关工具的使用

    点关注公众号,回复"1024"获取2TB学习资源! 今天我将详细的为大家介绍 MySQL 性能分析以及相关工具使用的相关知识,希望大家能够从中收获多多!如有帮助,请点在看.转发支持 ...

  3. 死磕数据库系列(二十):MySQL 数据库 DDL、DML、DQL、DCL 语言理论与实践(sql 8.0 版)...

    点关注公众号,回复"1024"获取2TB学习资源! 今天,民工哥带大家一起来学习一下 MySQL 数据库的 DDL.DML.DQL.DCL 这几种语言的理论知识与实践.如有帮助,请 ...

  4. 死磕数据库系列(三十五):MySQL 数据库性能监控

    点关注公众号,回复"1024"获取2TB学习资源! 前面给大家介绍了:MySQL 性能分析与相关工具的使用.今天我将详细的为大家介绍 MySQL 性能监控的相关知识,希望大家能够从 ...

  5. 死磕数据库系列(二十六):MySQL 高可用之单主、双主模型组复制配置实践

    点关注公众号,回复"1024"获取2TB学习资源! 前面我们学习:MySQL 高可用之组复制(MGR)技术的相关原理知识,今天我将详细的为大家介绍 MySQL 高可用技术组复制的单 ...

  6. 什么?还在用delete删除数据《死磕MySQL系列 九》

    别再用delete删除数据 系列文章 一.表空间 二.数据删除流程 三.实践全表删除表文件大小不改变 四.如何正确的减少磁盘文件 五.实践是检验认识是否具有真理性的唯一标准 六.开发建议 七.总结 系 ...

  7. S 锁与 X 锁的爱恨情仇《死磕MySQL系列 四》

    一网打尽MySQL的各种锁 系列文章 `获取MySQL各种学习资料可以联系咔咔` 前言 一.行锁 二.两阶段锁 三.理解死锁 四.优化你的代码尽量防止死锁 五.解释死锁的两种方案 六.如何解决热点数据 ...

  8. 一生挚友redo log、binlog《死磕MySQL系列 二》

    一生挚友redo log.binlog 系列文章 前言 一.redo log 二.如何根据项目情况设置innodb_log_file_size 二.binlog 三.什么是两阶段提交 四.为什么需要两 ...

  9. 聊聊MySQL的加锁规则《死磕MySQL系列 十五》

    大家好,我是咔咔 不期速成,日拱一卒 本期来聊聊MySQL的加锁规则,知道这些规则后可以判断SQL语句的加锁范围,同时也可以写出更好的SQL语句,防止幻读问题的产生,在能力范围内最大程度的提升MySQ ...

最新文章

  1. iOS实现传递不定长的多个参数
  2. 禁止冒名顶替Exchange用户发送邮件
  3. Linux 安装 luarocks(lua的模块管理工具)
  4. 2021阿里巴巴研发效能峰会来啦!
  5. emwin之在中断服务程序中创建窗口的结果
  6. 浏览器弹不出java_打开网址跳出弹窗“您的浏览器没有获得Java virtual machine 支持”,怎么办?...
  7. jquery div无法获取html文件,怎么样用jquery在div中加载页面
  8. 巨人退场!索尼前CEO平井一夫正式退休 结束35年索尼生涯
  9. TaskService API
  10. 呼吸灯 裸机 S3C2416
  11. Eclipse SQL Explorer
  12. python闯红灯检测斑马线检测红绿灯检测车速检测车流量统计车牌识别智慧交通系统
  13. 推动Web开放生态持续发展 百度正式发布Lavas解决方案
  14. oppo系统android版本下载,oppo手机助手
  15. FL studio20.9中文版水果编曲软件更新介绍
  16. iPhone软件开发完美起步
  17. 深度学习——手写数字识别
  18. 信息学奥赛一本通C++语言——1183:病人排队
  19. OFDM峰均比抑制matlab,一种降低OFDM峰均比的解决方法
  20. TMC429 - 三轴2相步进电机控制芯片

热门文章

  1. 识别户口本易语言代码
  2. 腾讯云服务器如何安装应用软件,腾讯云服务器Ubuntu环境下通过Apt-get安装软件...
  3. Taro:微信小程序通过获取手机号实现一键登录
  4. 2021易烊千玺高考成绩查询,2021高考进入倒计时 考生后援团送上祝福
  5. matlab半实物仿真,半实物仿真系统及半实物仿真方法
  6. 自我学习-逆向解析BOSS直聘cookie字段 _zp_stoken__加密
  7. 运放参数 分析 (LMC6482 为例)
  8. ESP32存储配网信息+LED显示配网状态+按键清除配网信息(附源码)
  9. ubuntu如何在多个工作区之间自由切换以及添加返回桌面图标
  10. 计算机原理(戴梅萼)