MySQL count(*)统计总数问题汇总

 更新时间:2022年09月20日 14:35:36   作者:一灯架构  
在日常开发工作中,我经常会遇到需要统计总数的场景,比如:统计订单总数、统计用户总数等,这篇文章主要介绍了MySQL count(*)统计总数的问题解析,需要的朋友可以参考下

在日常开发工作中,我经常会遇到需要统计总数的场景,比如:统计订单总数、统计用户总数等。一般我们会使用MySQL 的count函数进行统计,但是随着数据量逐渐增大,统计耗时也越来越长,最后竟然出现慢查询的情况,这究竟是什么原因呢?本篇文章带你一下学习一下。

1. MyISAM存储引擎计数为什么这么快?

我们总有个错觉,就是感觉MyISAM引擎的count计数要比InnoDB引擎更快,实际这不是错觉。

MyISAM引擎把表的总行数单独记录在磁盘上,查询的时候可以直接返回,不需要再累加统计。

但是当SQL查询中有where条件的时候,就无法再使用表的总行数了,还是需要乖乖的进行累加统计,查询性能也就跟InnoDB相差无几了。

为什么MyISAM引擎能够记录表的总行数,InnoDB引擎却不行?

因为MyISAM引擎不支持事务,只有表锁,所以记录的总行数是准确的。

而InnoDB引擎支持事务和行锁,存在并发修改的情况。又由于事务的隔离性,会出现不可重复读和幻读,记录的总行数无法保证是准确的。

2. 能不能手动实现统计总行数

既然InnoDB引擎没有帮我们记录总行数,我们能不能手动记录总行数,比如使用Redis。

其实也是不行的,使用Redis记录总行数,至少有下面3个问题:

  • 无法实现事务之间的隔离
  • 更新丢失,因为i++不是原子操作,当然可以使用Lua脚本实现原子操作,更复杂。
  • Redis是非关系型缓存数据库,不能当作关系型持久化数据库使用,一般需要设置过期时间。

由上图中得知,虽然Redis计数加1操作放在了事务里面,但是不受事务控制的,在事务没有提交前,其他查询依然读到了最新的总行数,这就是脏读的情况。

3. InnoDB引擎能否实现快速计数

有一种办法,可以粗略估计表的总行数,就是使用MySQL命令:

show table status like 'user';

真实的总行数有100万行,预估有99万多行,误差在可接受的范围内。

部分场景适用,比如粗略估计网站的总用户数。

4. 四种计数方式的性能差别

常见的统计总行数的方式有以下四种:

count(*) 、 count(常量) 、 count(id) 、 count(字段)

InnoDB引擎对count计数做了优化,会选用数据量较小的非聚簇索引进行统计。

比如用户表中有三个索引,分别是主键索引、name索引和age索引,使用执行计划查看计数的时候用到了哪个索引?

CREATE TABLE `user` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(100) DEFAULT NULL COMMENT '姓名',
  `age` tinyint NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`),
  KEY `idx_age` (`age`)
) ENGINE=InnoDB COMMENT='用户表';
explain select count(*) from user;

用到了数据量较小的age索引。

count(*) 、 count(常量) 是直接统计表中的总行数,效率较高。

而 count(id) 还需要把数据返回给MySQL Server端进行累加计数。

最后 count(字段)需要筛选不为null字段,效率最差。

四种计数的查询性能从高到低,依次是:

count(*) ≈ count(常量) > count(id) > count(字段)

对于大多数情况,得到计数结果,还是老老实实使用count(*)

所以推荐使用select count(*),别跟**select *搞混了,不推荐使用select ***的。

到此这篇关于MySQL count(*)统计总数的文章就介绍到这了,更多相关MySQL count(*)统计总数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 开启bin-log日志mysql报错的解决方法

    开启bin-log日志mysql报错的解决方法

    开启bin-log日志mysql报错:This function has none of DETERMINISTIC, NO SQL解决办法,大家参考使用吧
    2013-12-12
  • Idea 如何导入Mysql8.0驱动jar包

    Idea 如何导入Mysql8.0驱动jar包

    IDEA中的库(Libraries)就是用来存放外部jar包,我们的项目或模块需要某些jar包时,可以从这里把包导入到模块依赖(Dependencies)中,本文给大家介绍Idea 如何导入Mysql8.0驱动jar包,感兴趣的朋友一起看看吧
    2023-12-12
  • win8.1安装mysql5.6时遇到问题解决方案

    win8.1安装mysql5.6时遇到问题解决方案

    本文主要记录的是作者在win8.1安装mysql5.6时遇到问题的解决方案,网上查了很多方法都没能解决,这里把最后的方法分享给大家
    2016-10-10
  • 关于Mysql-connector-java驱动版本问题总结

    关于Mysql-connector-java驱动版本问题总结

    这篇文章主要介绍了Mysql-connector-java驱动版本问题,本文给大家介绍的很详细,通过原因说明问题小结个人建议给大家展示的很好,需要的朋友可以参考下
    2021-06-06
  • 详解MySQL 用户权限管理

    详解MySQL 用户权限管理

    这篇文章主要介绍了MySQL 用户权限管理的相关资料,帮助大家更好的理解和学习使用MySQL,感兴趣的朋友可以了解下
    2021-04-04
  • 解决SQL文件导入MySQL数据库1118错误的问题

    解决SQL文件导入MySQL数据库1118错误的问题

    在使用Navicat导入SQL文件时,有时会遇到报错问题,这通常与MySQL版本差异或严格模式设置有关,若报错提示rowsize长度过长,可能是因为MySQL的严格模式开启导致,解决方法是检查严格模式是否开启,若开启则需关闭
    2024-10-10
  • 详解MySQL如何避免全表扫描

    详解MySQL如何避免全表扫描

    这篇文章主要为大家详细介绍了为什么MySQL会执行全表扫描来解析查询,以及如何避免在大型表上进行不必要的全表扫描,有需要的小伙伴可以了解下
    2024-04-04
  • MySQL explain根据查询计划去优化SQL语句

    MySQL explain根据查询计划去优化SQL语句

    MySQL是一种常见的关系型数据库管理系统,常被用于各种应用程序中存储数据,当涉及到大量的数据时,就需要MySQL的explain功能来帮助优化,本文将详细介绍MySQL的explain功能,感兴趣的朋友可以参考阅读
    2023-04-04
  • mysql创建用户并赋予用户权限详细操作教程

    mysql创建用户并赋予用户权限详细操作教程

    这篇文章主要给大家介绍了关于mysql创建用户并赋予用户权限详细操作的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12
  • MySQL5.7限制general_log日志大小的实现

    MySQL5.7限制general_log日志大小的实现

    MySQL5.7.41中为避免通用查询日志general_log快速增长占用硬盘空间,可以通过定时任务执行脚本进行每日备份或清理,从而限制其大小,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-10-10

最新评论