天天看点

Mysql count(1) 、count(*)、count(字段)区别

以下针对Mysql count(1) 、count(*)、count(字段)区别围绕以下问题进行展开

​1、COUNT有几种用法?

2、COUNT(字段名)和COUNT(*)的查询结果有什么不同?

3、COUNT(1)和COUNT(*)之间有什么不同?

4、COUNT(1)和COUNT(*)之间的效率哪个更高?

5、为什么《阿里巴巴Java开发手册》建议使用COUNT(*)

6、MySQL的MyISAM引擎对COUNT(*)做了哪些优化?

7、MySQL的InnoDB引擎对COUNT(*)做了哪些优化?

8、上面提到的MySQL对COUNT()做的优化,有一个关键的前提是什么?

9、SELECT COUNT(*) 的时候,加不加where条件有差别吗?

10、COUNT(*)、COUNT(1)和COUNT(字段名)的执行过程是怎样的?​

  1. COUNT有几种用法?

  答:count(*) 、count(常量)、count(字段名)、count(distinct 字段名)

  1. COUNT(字段名)和COUNT(*)的查询结果有什么不同

  答:COUNT(字段名):符合条件的字段名进行统计,会判断字段是否为nul l,为Null不进行统计

        COUNT(*): 等同于count(1),会统计所有行,包含NUll

如果需要统计的表有没有辅助索引只有主键索引,将会以辅助索引进行统计,这也是innodb对select count(*)的优化,因为主键索引的叶子节点存储了主键和行数据的值,而辅助索引只存储了对应的主键索引和对应的主键索引的位置,所以辅助索引的索引树更低,所以统计的时候会优选辅助索引。

如果没有辅助索引会选择主键索引进行统计

mysql> show create table t1;(此时没有辅助索引)
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                 |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> desc select count(1) from t1;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | index | NULL          | PRIMARY | 4       | NULL |    7 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+

mysql> desc select count(*) from t1;
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | index | NULL          | PRIMARY | 4       | NULL |    7 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+---------+---------+------+------+----------+-------------+


mysql> show create table t1; (增加辅助索引)
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table                                                                                                                                                                                                        |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1    | CREATE TABLE `t1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(10) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 |
+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+


mysql> desc select count(*) from t1; 优选辅助索引(联合索引)进行统计
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key      | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t1    | NULL       | index | NULL          | idx_name | 43      | NULL |    7 |   100.00 | Using index |
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.06 sec)




      
  1. COUNT(1)和COUNT(*)之间有什么不同,哪个效率更高?

​对于count(1)和count(),MySQL的优化是完全一样的,根本不存在谁更快,但依旧建议使用count(),因为这是SQL92定义的标准统计行数的语法。

count(1) 会统计表中的所有的记录数,包含字段为 NULL 的记录,但它是用 1 代替了所有列,不在关注表中具体列的情况,count(*) 包括了所有的列,相当于行数,在统计结果的时候,它同样不会忽略为 NULL 的值。

4.为什么《阿里巴巴Java开发手册》建议使用COUNT(*)

因为COUNT()​是SQL92定义的标准统计行数的语法,并且效率高,所以请直接使用COUNT()查询表的行数

5.MySQL的MyISAM引擎对COUNT(*)做了哪些优化?

​MySQL MyISAM存储引擎,统计数据表的行数只需要O(1)复杂度,这是因为每张MyISAM的数据表都有一个meta信息有存储了row_count值。而一致性由表级锁来保证

6.MySQL的InnoDB引擎对COUNT(*)做了哪些优化?​

​InnoDB不能使用这种缓存操作,因为支持事务,大部分操作都是行级锁,行可能被并行修改,那么缓存记录不准确。

但是,InnoDB还是针对COUNT(*)语句做了些优化的。

通过低成本的索引进行扫表,而不关注表的具体内容。

InnoDB中索引分为聚簇索引(主键索引)和非聚簇索引(非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值。

MySQL会优先选择最小的非聚簇索引来扫表。

优化的前提是查询语句中不包含where条件和group by条件。

7.MySQL的InnoDB引擎对COUNT(*)做了哪些优化?

MyISAM:如果没有 WHERE 限制的话,MySQL直接返回保存有总的行数,而在有 WHERE 限制的情况下,总是需要对 MySQL 进行全表遍历。

InnoDB:如果没有 WHERE 限制的话通过遍历最小的可用的二级索引来处理 SELECT COUNT(*) 语句,而在有 WHERE 限制的情况下,会根据 WHERE 限制中选择遍历最小的可用的二级索引,没有则为全表遍历。

8.COUNT(*)、COUNT(1)和COUNT(字段名)的执行过程是怎样的?

COUNT(*) 包括了所有的列,相当于行数,在统计结果的时候,不会忽略列值为 NULL

COUNT(1) 包括了忽略所有列,用 1 代表代码行,在统计结果的时候,不会忽略列值为 NULL

继续阅读