MySQL select count(*)计数很慢优化方案
作者:一灯架构??????? 发布时间:2024-01-23 21:31:24
前言
在日常开发工作中,我经常会遇到需要统计总数的场景,比如:统计订单总数、统计用户总数等。一般我们会使用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 * 的。
来源:https://juejin.cn/post/7130276921534840845


猜你喜欢
- python在进行字符串的拼接时,一般有两种方法,一种是使用+直接相加,另一种是使用joina = "tests"b =
- re.findall()方法及re.compile()re.findall()在字符串中找到正则表达式所匹配的所有子串,并返回一个列表;如果
- python实现原图裁剪为固定尺寸小图的具体代码,供大家参考,具体内容如下讲解1、代码效果:实现原图裁剪为固定尺寸小图代码import nu
- 好了,下面我们看看如何在服务器上生成.m3u文件并下传到客户端的:<%dim choose,path,mydb,myset,
- 一、前言普通机器学习:从训练数据中学习一个假设。集成方法:试图构建一组假设并将它们组合起来,集成学习是一种机器学习范式,多个学习器被训练来解
- 多线程多线程是个提高程序运行效率的好办法,本来要顺序执行的程序现在可以并行执行,可想而知效率要提高很多。但是多线程也不是能提高所有程序的效率
- 今晚开放ecmall商城的QQ登陆功能,在回调时产生错误,file_get_contents函数执行时,没有抓取到正确的信息,于是改用cur
- 1、安装AnacondaAnaconda指的是一个开源的Python发行版本,其包含了conda、Python等180多个科学包及其依赖项。
- 前言项目中一般分测试环境(QAS),生产环境(PRD),当我们的项目经历了一次周期跨度较长的更新后,当我们发布到生产环境时,首要的任务是将新
- 有时在处理不规则数据时需要提取文本包含的时间日期。dateutil.parser模块可以统一日期字符串格式。datefinder模块可以在字
- 首先恭喜月影,当然希望好书大卖!原文提供了样章下载1.1M,pdf格式的。如果大家想下载可以访问源地址:http://bbs.51js.co
- 一、连接MySQL(和PHP搭配之最佳组合)格式: -h主机地址 -u用户名 -p用户密码例1:连接到本机上的MySQL。首先在打开DOS窗
- 安装好jupyter notebook后,在pycharm中无论运行什么样的python脚本,都会默认使用python的console运行,
- 前言最近在写一个移动端的地图项目,也是首次完整的去了解百度地图api,这篇博客会手把手的教你如何使用百度地图api和一些常见问题,后续我也会
- 步骤:一、新建文本文档xxx.txt,修改文件类型为.udl二、打开该文件,在《提供数据》中找到对应的服务。三、在连接中选择需要的数据库,并
- 看代码吧~def find_all_index(arr, item): return [i for i, a in
- 案例一 导入图片思路: 1.导入库 2.加载图片 3.创建窗口 4.显示图片 5.暂停窗口 6.关闭窗口# 1.导入库import cv2#
- mapmap(function,iterable)x = [1,2,3,4,5]def square(num): return num*nu
- 在团队意见PK中,运用对方的知识背景说服对方,这就是技术性击倒。这样通常能把对方驳得哑口无言,我经常被这样击倒,甚至觉得怎么那么多牛逼的设计
- 本文实例讲述了Python基于正则表达式实现文件内容替换的方法。分享给大家供大家参考,具体如下:最近因为有一个项目需要从普通的服务器移植到S