我的编程空间,编程开发者的网络收藏夹
学习永远不晚

浅谈MySQL 统计行数的 count

短信预约 信息系统项目管理师 报名、考试、查分时间动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

浅谈MySQL 统计行数的 count

MySQL count() 函数我们并不陌生,用来统计每张表的行数。但如果你的表越来越大,且是 InnoDB 引擎的话,会发现计算的速度会越来越慢。在这篇文章里,会先介绍 count() 实现的原理及原因,然后是 count 不同用法的性能分析,最后给出需要频繁改变并需要统计表行数的解决方案。

Count() 的实现

InnoDB 和 MyISAM 是 MySQL 常用的数据引擎,由于两者实现的不同,导致 count() 操作计算的效率也不同。

对于 MyISAM 来说,它把每个表的总行数都存在了磁盘上,因此使用 count(*) 计算时,效率很高直接返回结果。但如果加入了 where 条件,依然会进行搜索,所以效率是不高的。

对于 InnoDB 来说,在进行 count(*) 运算时,会把数据从引擎中一行行读出来,然后累计计数,自然表大了之后,效率就变低了。

那么,为什么 InnoDB 不能像 MyISAM 在表中记录呢?原因就在于 InnoDB 比 MyISAM 多了支持事务的特性,同时也需要一定的取舍。由于 MVCC 的控制,使得 MySQL 具有并发的能力,也就是说对于同一时刻,InnoDB 返回的表的行数是不一定的,事务看到的行数与开启后的一致性视图有关,换句话说,每个事务能看到的数据版本是不一样的,只能一行行拿出来进行判断。

像下面的事务,假设表 t 有 10000 条数据:

Session A Session B Session C
select count(*) from t;
insert into t ();
begin;
insert into t();
select count(*) from t; select count(*) from t; select count(*) from t;
10000; 结果是 10002 结果是 10001

对于 Session A 来说,Session B 未提交不可见,Session C 提交了,但是在 Session A 启动后提交的,也不可见。所以是 10000.

而对于 Session B 而言,Session C 在启动之前提交,自己又插入了一条,所以结果是 10002.

其实 InnoDB 在进行 count(*) 操作时,还是做了优化的,在进行 count(*) 操作时,由于普通索引会保存主键的 id 值,所以会找到最小的那颗普通索引树进行查找,而不是去遍历主键索引树。

在保证逻辑正确的前提下,减少扫描的数据量,是数据库系统设计的通用法则。

另外在使用 show table status 时,也可以查询出行数,而且速度很快,但需要注意的是,该命令是通过索引统计的值来采样估算的。官方文档说误差可以有 40%-50%.

但如果我们真的需要实时的获取的某个表的行数,应该怎么办呢?

手动保存表的数量

用缓存系统来保存计数

对于进行更新的表,可能会想到用缓存系统来支持。比如 Redis 里来保存某个表总行数。

每次插入数据库时,Redis 计数加一,相反则减一,这样看起来读写操作都很快,但会存在一些问题。

缓存系统会丢失更新:

对于 Redis 在内存中的数据,需要定期的同步到磁盘中,但对于 Redis 异常重启,就没有办法了。比如在 Redis 中插入后,Redis 重启,数据没有持久化到硬盘。这时可以在重启 Redis 后,从数据库执行下 count(*) 操作,然后更新到 Redis 中。一次全表扫描还是可行的。

逻辑不精确:

假设一个页面中,需要显示一张表的行数,以及每一条数据。在实现时,可以先从 Redis 取数量,然后从数据库里取记录。

但可能会出现这样的情况:

  1. 数据库查到 100 行结果里有最新插入的记录,而 Redis 计数里少 1.
  2. 数据库查到 100 行结果没有最新的记录,但 Redis 计数却多了 1.
Session A Session B
插入一条数据; T1
读 Redis 计数; T2
从数据库中查记录;
Redis 计数加 1; T3

对于 Session B 来说,在 T2 时刻,会发现 Redis 的数量比数据库少 1 条。

Session A Session B
Redis 计数加 1; T1
读 Redis 计数; T2
从数据库中查记录;
插入一条数据; T3

对于 Session B 来说,在 T2 时刻,会发现 Redis 的数量比数据库多 1 条。

其实产生问题的原因就是因为 Redis 和数据库查记录没有在同一个事务中。

用数据库保存

由于 InnoDB 引擎的支持,MySQL 本身是支持事务的,所以将 Redis 的插入操作换成在数据库的更新操作,就可以利用在RR级别下的事务特性,进而保证数据的精确性。

而且还有一点,由于 redo log 的支持,在 MySQL 发生异常时,是可以保证 crash-safe。

不同 count 用法的执行效率

count() 本身是一个聚合函数,对于返回的结果集,一行行地判断。如果参数不是 NULL 的话,会一直累加,最后返回结果。

所以 count(*), count(id), count(1) 表示都是返回满足条件的结果集总行数。

而 count(字段),则表示满足条件的数据行里,不为 NULL 的字段。

对于 count(id) 来说,InnoDB 会遍历整张表,把每行 id 取出来,给 server 层。Server 判断 id 是否为空,然后累加。

对于 count(1) 来说,InnoDB 会遍历整张表,但不取值。Server 层会自己放入 1,然后累加。

所以对于 count(1) 的执行会比 count(*) 要快,少了解析数据行以及拷贝字段值的操作。

对于 count(字段) 来说,如果字段定义时是 not null, 会一行行读出,并判断不能为 null,然后累加。如果定义时可以为 null,执行时,需要将值去除,判断不是 null 才累加。

count(*) 除外,专门做了优化,不取值,直接按行累加,并且会找到最小的索引树进行计算。

总结

MySQL count() 函数的执行效率和底层的数据引擎有关。MyISAM 不加 where 条件,查询会很快,但不支持事务。InnoDB 支持事务,由于 MVCC 的实现,导致每次查询都需要一行行的扫描,效率不高。

解决方法可以通过设计外部缓存如 Redis,保存记录。但存在异常重启和数据不准确的情况。可以通过在 InnoDB 中新建一张表,保存记录这样的解决方案。

最后,InnoDB 对 count(*) 做了独立的优化,而其他的 count 操作,则需要额外的操作。

以上就是浅谈MySQL 统计行数的 count的详细内容,更多关于Mysql count的资料请关注自学编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

浅谈MySQL 统计行数的 count

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

浅谈MySQL 统计行数的 count

MySQL count() 函数我们并不陌生,用来统计每张表的行数。但如果你的表越来越大,且是 InnoDB 引擎的话,会发现计算的速度会越来越慢。在这篇文章里,会先介绍 count() 实现的原理及原因,然后是 count 不同用法的性能
2022-05-31

MySQL统计函数count详解

MySQL统计函数count详解 1. count()概述2. count(1)和count(*)和count(列名)的区别3. count(*)的实现方式 1. count()概述 count() 是一个聚合函数,返回指定匹配
2023-08-17

浅析MySQL的基数统计

一、基数是啥? Cardinality指的就是MySQL表中某一列的不同值的数量。 如果这一类是唯一索引,那基数 = 行数。 如果这一列是sex,枚举类型只有男女,那它是基数就是2 Cardinality越高,列就越有成为索引的价值。MyS
2022-05-26

MySql统计函数COUNT的具体使用详解

目录1. COUNT()函数概述2. COUNT()参数说明3. COUNT()判断存在4. COUNT()阿里开发规范1. COUNT()函数概述COUNT() 是一个聚合函数,返回指定匹配条件的行数。开发中常用来统计表中数据,全部数据
2022-08-14

COUNT在数据去重统计的实践

在数据去重统计中,COUNT函数可以帮助我们统计去重后的数据条目数量。下面是一个实践示例:假设我们有一个包含重复数据的表格,如下所示:IDName1Alice2Bob3Alice4Bob5Alice我们希望统计去重后的数据条目
COUNT在数据去重统计的实践
2024-08-11

浅谈MySQL 亿级数据分页的优化

目录背景分析数据模拟1、创建两个表:员工表和部门表2、创建两个函数:生成随机字符串和随机编号3、编写存储过程,模拟500W的员工数据4、编写存储过程,模拟120的部门数据5、建立关键字段的索引,这边是跑完数据之后再建索引,会导致建索引耗时长
2022-05-27

COUNT统计特定条件下的记录数

COUNT可以用来统计特定条件下的记录数。例如,如果想要统计一个数据库表中age大于等于18的记录数,可以使用以下SQL语句:SELECT COUNT(*) FROM table_name WHERE age >= 18;这将返回age大
COUNT统计特定条件下的记录数
2024-08-11

COUNT在数据库统计中的重要性

COUNT是数据库中的一个重要函数,用于统计某个列或表中的行数。在数据库统计中,COUNT函数可以帮助我们快速获取数据的数量信息,帮助我们进行数据分析和决策。COUNT函数通常用于以下几个方面:统计数据行数:通过COUNT函数,我们可以快
COUNT在数据库统计中的重要性
2024-08-10

浅谈MySQL8和MySQL5.7在自增计数上的区别

目录Auto-Incrementmysql 5.7 的自增MySQL 8 的自增持久化示例对比MySQL 8 的解决方案总结Auto-Increment自增(Auto-Increment)计数功能可以为主键列生成唯一值,这是数据库的一种设
2023-10-09

跨数据库统计:不同SQL方言的COUNT

在跨数据库统计时,不同SQL方言的COUNT函数的用法略有不同。MySQL:在MySQL中,COUNT函数的用法如下:SELECT COUNT(column_name) FROM table_name;如果要统计所有行数,则可以使用通配符
跨数据库统计:不同SQL方言的COUNT
2024-08-10

浅谈MySql update会锁定哪些范围的数据

目录1、背景2、前置知识2.1 数据库的隔离级别2.2 数据库版本2.3 数据库的存储引擎2.4 锁是加在记录上还是索引上2.5 update...where加锁的基本单位是2.6 行级锁3、测试数据加锁3.1 唯一索引测试3.2 普通索引
2022-06-24

编程热搜

目录