大家都在用MySQL count(*)统计总数,到底有什么问题?

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

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

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

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

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

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

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

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

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

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

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

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

大家都在用MySQL count(*)统计总数,到底有什么问题?

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

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

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

show table status like 'user';

大家都在用MySQL count(*)统计总数,到底有什么问题?

真实的总行数有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;

大家都在用MySQL count(*)统计总数,到底有什么问题?

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

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

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

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

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

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

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

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

大家都在用MySQL count(*)统计总数,到底有什么问题?

Original: https://www.cnblogs.com/yidengjiagou/p/16709424.html
Author: 一灯架构
Title: 大家都在用MySQL count(*)统计总数,到底有什么问题?

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/586930/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 简单的python爬虫保存百度、360 搜索内容到数据库

    import requests import re from pyquery import PyQuery as Pq import pymysql.cursors connect…

    Java 2023年6月16日
    092
  • Redis安装(CentOS 8.5 64位)

    Redis安装 1. 准备工作 1.1 下载安装包 官网下载地址:https://redis.io/ 1.2 传输文件到服务器 使用ssh工具连接到服务器,把下载好的文件上传到服务…

    Java 2023年6月5日
    092
  • 使用 CompeletedFuture 实现异步调用

    在我们平时写的项目中,异步调用是一个比较重要的优化手段,在 Java 中,提供了 CompletedFuture 供我们使用,具体实现如下: 例子 假如现在有一个需求,我需要去淘宝…

    Java 2023年6月9日
    064
  • 【MySQL】order by引起的慢查询问题总结

    最近遇到了一个SQL没有走索引导致出现慢查询的问题,SQL本身很简单,两张表联合查询然后进行排序和分页,由于涉及到一些业务,这里以用户表和订单表为例,用户表数据在35W左右,订单表…

    Java 2023年6月8日
    082
  • MySQL基础(2)

    MySQL服务器支持SQL,因此,如何通过SQL告知MySQL服务器如何完成各种数据管理操作,就是重中之重。要想和服务器做好交流,则必须熟练掌握它。当使用某个程序(如mysql客户…

    Java 2023年6月5日
    083
  • Gradle连载6-AndroidGradle任务之defaultConfig配置

    一、android工程配置 buildscript { repositories { jcenter() } dependencies { classpath ‘com.andro…

    Java 2023年6月13日
    091
  • JavaWeb-Servlet基础

    前言 Servlet是 JavaWeb中最核心的组件. Servlet规范为 JavaWeb应用制定了对象模型: 请求对象(ServletRequest): Servlet从该对象…

    Java 2023年5月29日
    066
  • Spring boot 注意问题 !!

    1,lombok在pom文件中需要引入正确版本,否则会导致maven的complier无法正常导入!!, 当前正确配置: java;gutter:true;org.projectl…

    Java 2023年5月30日
    075
  • 大顶堆的实现(基于数组存储的完全二叉树)

    完全二叉树 完全二叉树的定义 满二叉树非完全二叉树,非满二叉树完全二叉树 完全二叉树的特点 叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。 完全二叉树的实现 …

    Java 2023年6月13日
    065
  • 【校招VIP】[产品][一本][6分]简历原则上写一页

    关注 【校招VIP】公众号,回复 【简历】,添加校招顾问微信,即可获取简历指导! 简历背景:21届一本产品 简历评分: 6分 一、学员简历 ​ ​ ​ 二、 指导意见: 简历有两大…

    Java 2023年6月5日
    092
  • 性能测试案例全过程方案八———混合场景设计(多线程组并发运行)

    JMeter压力测试(一)中设置线程组的线程数,即执行时的并发用户数,适用于单个线程组的并发测试。 如果测试需求出现如下场景,该如何使用JMeter实现压力测试呢?即JMeter如…

    Java 2023年5月30日
    0102
  • SpringBoot 整合 MongoDB 实战解说

    在前面的文章中,我们详细的介绍了 MongoDB 的配置和使用,如果你对 MongoDB 还不是很了解,也没关系,在 MongoDB 中有三个比较重要的名词: 数据库、集合、文档!…

    Java 2023年6月9日
    086
  • 实验设计

    统计学是什么? 统计学是对令人困惑费解的问题作出 数字设想的艺术 一、对照实验 该部分的第一个例子由脊髓灰质炎的疫苗引入了 随机对照双盲实验。 其所总结出的实验设计的原则: 减小混…

    Java 2023年6月7日
    076
  • roketmq安装和运行

    软件下载: 链接:https://pan.baidu.com/s/1CRFQyQrVsKQHFTkU5m3-Hg提取码:gejx复制这段内容后打开百度网盘手机App,操作更方便哦 …

    Java 2023年5月30日
    076
  • Java开发笔记(一百五十四)StringBuffer和StringBuilder的由来

    本来String类已经能够完成字符串操作的所有功能,为何Java又提供了专门的StringBuffer和StringBuilder呢?这要从String类的设计说起了,查看Stri…

    Java 2023年6月6日
    075
  • Spring 拦截器

    拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行 作用: 在指定的方法调用前后执行预先设定的代码 阻止原始方法的执行 总…

    Java 2023年6月7日
    071
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球