数据库中count(1)的用法_MySQLlimit

数据库中count(1)的用法_MySQLlimit本文介绍 MyISAM 和 InnoDB 如何执行 count 操作,如果是一个需要使用 count 进行大量计数的场景,应该如何设计实现,以及不同 count 操作的效率。

MySQL45讲之count操作 - flowers

前言

本文介绍 MyISAM 和 InnoDB 如何执行 count 操作,如果是一个需要使用 count 进行大量计数的场景,应该如何设计实现,以及不同 count 操作的效率。

MyISAM和InnoDB的count

MyISAM

MyISAM 存储引擎的每个表记录了总行数,在没有 where 条件时,直接获取该记录值返回。

InnoDB

InnoDB 获取 count 值,只能通过扫描索引树来计数。

为什么 InnoDB 只能临时扫描来计数,而不能像 MyISAM 一样存储一个总行数值?
对于同一时刻的多个查询请求,因为并发版本控制的原因,InnoDB 表应该返回多少行是不确定的,需要扫描索引,判断每行记录的可见性。

此外,InnoDB 也做了一些优化。主键索引树存储了行记录,而普通索引树只存储主键值,所以普通索引树比主键索引树小很多。因此,MySQL 会优先选择最小的索引树来遍历。在保证逻辑正确的情况下,尽量减少扫描的数据量,是数据库系统设计的通用法则之一。

count值如何记录

1、缓存记录

比如在 Redis 中用 string 类型记录一个计数,当新增或者删除记录时,相应修改 Redis 的值。

这样是不行的,没法保证数据的一致性

首先,如果业务系统插入或删除一行数据后,系统宕机,Redis 没有写入,重启系统后 Redis 会与数据库不一致。不过,这个问题可以通过系统重启时从数据库查询一次解决。

而且,如果需要同时从 Redis 和数据库中查询数据,两者无法保证数据一致,比如从 Redis 中取出表总行数和从数据库中取出前 100 行数据。因为并发请求,只要从 Redis 和 MySQL 查询数据的操作不是原子的,数据就不是一致的。

2、数据库统计表记录

数据库新建一个统计表记录行数。那不是和前一个方法一样么,并发请求下得到的结果可能不一致。

可以的,行数据和统计数据同时存在数据库中,并且数据库支持事务,所以可以将多个操作封装成原子的,保证数据一致。

多种count操作的效率

count(主键id)

存储引擎遍历表拿到行记录返回,server 层解析出 id 值,判断是否为 null,统计行数。

count(1)

存储引擎遍历表不取值,server 层对于每一行放进去一个 1,判断是否为 null,统计行数。

因为 server 层需要解析引擎返回的结果拿到 id,所以 count(1) 比 count(主键id) 高效。

count(字段)

存储引擎遍历表取出字段返回,server 层解析,判断字段是否为 null,统计行数。

count(*)

MySQL 进行了优化,存储引擎遍历表不取值,server 层判断是否为 null,逐行累加。

效率从高到低:count(*) ≈ count(1) > count(主键id) > count(字段)

提问

在刚刚讨论的方案中,我们用了事务来确保计数准确。由于事务可以保证中间结果不被别的事务读到,因此修改计数值和插入新记录的顺序是不影响逻辑结果的。

但是,从并发系统性能的角度考虑,你觉得在这个事务序列里,应该先插入操作记录,还是应该先更新计数表呢?

先执行插入操作,再执行更新操作。从并发系统性能的角度考虑,应该尽可能减少锁等待,而更新操作需要加行锁,行锁在事务提交之后才会释放。所以最后执行更新操作,减少锁等待,提高并发度。

参考

  • [1] count这么慢,我该怎么办

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/5854.html

(0)
上一篇 2023-04-22
下一篇 2023-04-22

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注