MySQL45讲之count操作

本文介绍 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、数据库统计表记录

在数据库中创建一个新的统计表,以记录行数。这与前面的方法相同,并且来自并发请求的结果可能不一致。

[En]

Create a new statistical table in the database to record the number of rows. That’s the same as the previous method, and the results from concurrent requests may be inconsistent.

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

多种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(字段)

在刚才讨论的场景中,我们使用事务来确保准确计数。由于事务可以确保中间结果不会被其他事务读取,因此修改计数值和插入新记录的顺序不会影响逻辑结果。

[En]

In the scenario just discussed, we used transactions to ensure accurate counting. Because transactions can ensure that the intermediate results will not be read by other transactions, the order in which the count values are modified and new records are inserted does not affect the logical results.

但是,从并发系统性能的角度来看,您认为在这个事务序列中,是应该先插入操作记录,还是应该先更新盘点表?

[En]

However, from the perspective of concurrent system performance, do you think that in this transaction sequence, should the operation record be inserted first, or should the count table be updated first?

在更新操作之前执行插入操作。从并发系统性能的角度来看,应该尽可能减少锁等待,而更新操作需要锁定,直到事务提交才会释放行锁。因此,最后执行更新操作以减少锁等待,提高并发度。

[En]

Perform the insert operation before the update operation. From the perspective of concurrent system performance, lock waiting should be reduced as much as possible, while update operations need to be locked, and row locks are not released until the transaction is committed. So finally, the update operation is performed to reduce the lock waiting and improve the degree of concurrency.

Original: https://www.cnblogs.com/flowers-bloom/p/mysql45-count.html
Author: flowers-bloom
Title: MySQL45讲之count操作

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

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

(0)

大家都在看

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