欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

MySQL count(*)太慢怎么办

程序员文章站 2022-03-26 18:24:17
1、count(*)实现方式MyISAM引擎把表的总行数存在磁盘上,在没有where条件的时候,如果执行count(*),会直接返回这个数。InnoDB引擎在执行count(*)时,需要把数据一行一行地读出来,累积计数。这是由于InnoDB事务默认的隔离级别是可重复读,可重复读是通过多版本并发控制(MVCC)实现的,一个会话在执行count(*)的时候,要依次判断表中的每一行是否可见,可见的行进行累积计数。此外,InnoDB是索引组织表,普通索引树比主键索引树小很多,所以在进行count(*)时,优化器...

1、count(*)实现方式

MyISAM引擎把表的总行数存在磁盘上,在没有where条件的时候,如果执行count(*),会直接返回这个数。

InnoDB引擎在执行count(*)时,需要把数据一行一行地读出来,累积计数。这是由于InnoDB事务默认的隔离级别是可重复读,可重复读是通过多版本并发控制(MVCC)实现的,一个会话在执行count(*)的时候,要依次判断表中的每一行是否可见,可见的行进行累积计数。此外,InnoDB是索引组织表,普通索引树比主键索引树小很多,所以在进行count(*)时,优化器会寻找最小的那棵树来遍历。

2、解决方法:将计数保存在数据库中

把计数直接放到数据库中单独一张计数表中,当表中插入一行的时候,就计数表中的计数值就加1,当删除一行的时候,计数表中的计数值就减1。由于InnoDB是支持崩溃恢复数据的,因此这种做法不用担心因系统崩溃而导致的计数丢失。此外,InnoDB是支持事务的,默认的隔离级别是可重复读,因此对于可以保证数据的逻辑一致性。

如图可见,如果使用缓存保存计数,那么由于在并发系统中,我们不能控制不同线程的执行时刻,所以会出现计数值逻辑上不精确的情况。在T2时刻,会话A将计数加1,在T3时刻,会话B读计数时,计数已经加了1,但是却不能查到新加入的记录,因为这条记录在T4时刻才被会话A插入。而使用数据库保存计数就不会出现这种情况。
MySQL count(*)太慢怎么办
MySQL count(*)太慢怎么办
并且,从并发性能的角度来看,我们应该先插入一行数据,再将计数加1,因为更新计数表设计到行锁的竞争,行锁在需要的时候加上,不需要不会立刻释放,而是要等到事务提交的时候才会释放,因此容易引起锁冲突的语句要尽量往后放。

3、不同count的性能

count(*)、count(主键)、count(1)表示返回满足条件的数据行的总行数;count(字段)表示返回满足条件的数据行里面,参数"字段"不为null的总行数。

count(主键):遍历整张表,把每一行的主键id值取出来,返回给server层,server层拿到id后,按行累加,不会忽略列值为null。

count(1):遍历整张表,但不取值,返回每一行给server层,用1代表代码行,按行累加,不会忽略列值为null。count(1)优于count(主键id),因为count(主键id)要额外做解析数据行,拷贝字段值的操作。

count(字段):只包括参数"字段"那一列,在统计结果的时候,会忽略字段值为null的计数。因此,需要做额外的判断字段是否为null的操作。

count(*):包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为NULL。MySQL对count(*)做了优化,最简单的执行办法是找一列定义为NOT NULL的列,如果该列有索引,则使用该索引,当然,为了性能,SQL Server会选择最窄的索引以减少IO。

按照效率,count(字段) < count(主键) < count(1)约等于count(*)。

本文地址:https://blog.csdn.net/Longstar_L/article/details/107372696