聊聊MySQL的COUNT的性能,看看怎么最快?

数据库 MySQL
这篇文章主要介绍了聊聊MySQL的COUNT(*)的性能,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

[[400316]]

前言

基本职场上的程序员用来统计数据库表的行数都会使用count(*),count(1)或者count(主键),那么它们之间的区别和性能你又是否了解呢?

其实程序员在开发的过程中,在一张大表上统计总行数是非常耗时的一个操作,那么我们应该用哪个方法统计会更快呢?

接下来我们就来聊一聊MySQL中统计总行数的方法和性能。

count(*),count(1),count(主键)哪个更快?

1、建表并且插入1000万条数据进行实验测试:

  1. # 创建测试表 
  2. CREATE TABLE `t6` ( 
  3.  `id` int(11) NOT NULL AUTO_INCREMENT, 
  4.  `namevarchar(50) NOT NULL
  5.  `status` tinyint(4) NOT NULL
  6.  PRIMARY KEY (`id`), 
  7.  KEY `idx_status` (`status`) 
  8. ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 
  9.   
  10. # 创建存储过程插入1000w数据 
  11. CREATE PROCEDURE insert_1000w() 
  12. BEGIN 
  13.   DECLARE i INT
  14.   SET i=1; 
  15.   WHILE i<=10000000 DO 
  16.     INSERT INTO t6(name,status) VALUES('god-jiang-666',1); 
  17.     SET i=i+1; 
  18.   END WHILE; 
  19. END
  20.   
  21. #调用存储过程,插入1000万行数据 
  22. call insert_1000w(); 

2、分析实验结果

  1. # 花了0.572秒 
  2. select count(*) from t6; 

 

在这里插入图片描述

  1. # 花了0.572秒 
  2. select count(1) from t6; 

 

  1. # 花了0.580秒 
  2. select count(id) from t6; 

 

  1. # 花了0.620秒 
  2. select count(*) from t6 force index (primary); 

 

从上面的实验我们可以得出,count(*)和count(1)是最快的,其次是count(id),最慢的是count使用了强制主键的情况。

下面我们继续测试一下它们各自的执行计划:

  1. explain select count(*) from t6; 
  2. show warnings; 

 

  1. explain select count(1) from t6; 
  2. show warnings; 

 

  1. explain select count(id) from t6; 
  2. show warnings; 

 

  1. explain select count(*) from t6 force index (primary); 
  2. show warnings; 

 

从上面的实验可以得出这三点:

  1. count(*)被MySQL查询优化器改写成了count(0),并选择了idx_status索引
  2. count(1)和count(id)都选择了idx_statux索引
  3. 加了force index(primary)之后,走了强制索引

这个idx_status就是相当于是二级辅助索引树,目的就是为了说明:InnoDB在处理count(*)的时候,有辅助索引树的情况下,会优先选择辅助索引树来统计总行数。

为了验证count(*)会优先选择辅助索引树这个结论,我们继续来看看下面的实验:

  1. # 删除idx_status索引,继续执行count(*) 
  2. alter table t6 drop index idx_status; 
  3.  
  4. explain select count(*) from t6; 

 

从以上实验可以得出,删除了idx_status这个辅助索引树,count(*)就会选择走主键索引。所以结论:count(*)会优先选择辅助索引,假如没有辅助索引的存在,就会走主键索引

为什么count(*)会优先选择辅助索引?

在MySQL5.7.18之前,InnoDB通过扫描聚集索引来处理count(*)语句。

从MySQL5.7.18开始,InnoDB通过遍历最小的可用二级索引来处理count(*)语句。如果不存在二级索引,则扫描聚集索引。

新版本为何会使用二级索引来处理count(*)呢?

因为InnoDB二级索引树的叶子节点上存放的是主键,而主键索引树的叶子节点存放的是整行数据,所以二级索引树比主键索引树小。因此查询优化器基于成本考虑,优先选择的是二级索引。所以索引count(*)快于count(主键)。

总结

这篇文章的结论就是count(*)=count(1)>count(id)。

为什么count(id)走了主键索引还会更慢呢?因为count(id)需要取出主键,然后判断不为空,再累加,代价更高。

count(*)是会总计出所有NOT NULL和NULL的字段,而count(id)是不会统计NULL字段的,所以我们在建表的尽量使用NOT NULL并且给它一个默认是空即可。

最后,在以后总计数据库表的总行数的时候,可以大胆的使用count(*)或者count(1)。

参考资料

  • 《高性能MySQL》(第三版)第六章优化COUNT()查询
  • 《MySQL实战45讲》林晓斌

 

责任编辑:姜华 来源: 爱写Bug的麦洛
相关推荐

2022-07-27 14:24:38

MySQL数据库SQL

2018-07-19 08:49:47

Python编程语言测评

2021-12-02 07:02:16

API性能设计

2020-11-11 10:00:13

NAT性能内核

2015-05-19 09:28:17

网速

2022-11-17 00:04:38

接口性能查询

2009-03-22 19:19:15

多核多核服务器多核历史

2020-06-10 08:28:51

Kata容器I

2023-11-09 11:56:28

MySQL死锁

2021-11-17 08:11:35

MySQL

2023-06-12 09:09:19

MySQLDDLNSTANT

2023-07-12 13:08:58

性能测试数据

2022-04-02 10:23:12

MySQL数据库

2022-11-26 08:16:26

2024-02-29 18:06:39

HTTP性能优化

2020-10-12 09:38:46

iPhone数据迁移苹果

2022-06-30 08:01:53

mysqlmyisamcount

2021-07-02 07:06:20

调试代码crash

2021-11-18 08:20:22

接口索引SQL

2022-03-11 10:23:02

React性能优化
点赞
收藏

51CTO技术栈公众号