禅道博客

分享专业技术知识,文章内容干货满满

Count的实现方式

2022-11-17 17:11:00
代婷婷
原创 63
摘要:在不同的mysql引擎中,count(*)有不同的实现方式。

在不同的mysql引擎中,count(*)有不同的实现方式。


MYISAM引擎把一个表的总行数存在了磁盘上,执行count(*)时直接返回,效率很高。如果加了where条件myisam也不会返回的这么快。

InnoDB执行count(*)时,把数据一行一行的从引擎里面读出来,然后累计计数。

InnoDB每一行记录都要判断是否对这个会话可见,所以只能一行一行的读出数据进行判断,可见的行才能计入当前这个查询的总行数。

InnoDB是组织索引表,主键索引树的叶子节点是数据,普通索引树的叶子节点是主键值。普通索引树比主键索引树小,count(*)遍历哪个索引树逻辑上是一样的,mysql优化器会找到最小的那棵树来遍历。保证逻辑正确的前提下,尽量减少扫描的数据量,是数据库系统设计的通用法则之一。

show table status 命令,输出结果里面也有一个TABLE_ROWS用于显示表当前有多少行,TABLE_ROWS是从采样估算来的,所以不是很准确,误差可能达到40%-50%,所以不能直接用TABLE_ROWS。

MyISAM引擎count(*)很快,但不支持事务;

Show table status 返回很快,但不准确;

InnoDB引擎直接count(*)会遍历全表,结果准确,会导致性能问题。

一、用缓存系统保存计数

更新很频繁的库,用缓存系统来支持,可以用一个redis服务来保存这个表的总行数,这个表每被插入一行,Redis计数就加一,每被删除一行Redis计数就减1,读和更新都会很快,但是缓存系统可能会丢失更新,比如Redis服务异常重启了

将计数保存到缓存系统中,可能会丢失更新,也会逻辑上不精确。

两种情况:

   1. 查到的 100 行结果里面有最新插入记录,而 Redis 的计数里还没加 1;

   2. 查到的 100 行结果里没有最新插入的记录,而 Redis 的计数里已经加了 1

二、 在数据库保存计数

利用事务,逻辑上可以保持一致,

会话A将计数值加1->会话B读计数值,取最近的100条数据->会话A插入一行数据

会话B执行的时候会话A还没有提交,所以对会话B是不可见的,逻辑上是一致的

按照效率排序的话,count(字段)
发表评论
评论通过审核后显示。