首页 > 技术文章 > mysql select count性能及使用

ls-shiyi 2019-10-24 21:10 原文

前言

       select count是我们在mysq经常使用的计算数据个数的sql,主要用法有三种,count(*),count(常量),count(列)。这三种在使用上及效率的区别呢?

正文

扫描的行数

       首先对于效率来说,如下的一张表:

CREATE TABLE `tb_user_info` (
  `id` bigint(20) NOT NULL COMMENT 'id',
  `user_name` varchar(0) COLLATE utf8mb4_bin NOT NULL COMMENT '用户名',
  `phone` varchar(0) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '手机号',
  `sex` int(11) NOT NULL COMMENT '性别',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
)

       我们执行相应的count sql,列名、 常量 和 * 这三个条件中,常量 是一个固定值,肯定不为NULL。* 可以理解为查询整行,所以肯定也不为NULL,那么就只有列名的查询结果有可能是NULL了。所以, COUNT(常量) 和 COUNT(*)表示的是直接查询符合条件的数据库表的行数。而COUNT(列名)表示的是查询符合条件的列的值不为NULL的行数。

       而对于count(*)的效率来说,又要分为MyISAM和InnoDB,MyISAM由于是表级的锁,可以做相应的优化将表的总行数记录了下来,因此不需要扫描全表;而对于现在相对普遍的InnoDB引擎,由于是行级的锁,无法记录表的总行数,因此大多需要扫描表中数据。

InnoDB索引的利用

       InnoDB引擎的count能否用到索引,又要分为是否有where条件。

count后不跟where条件

       不跟where条件,count(*)和count(常量)由于不需要关心列中的数据,因此都会使用到索引,优先占用空间较小的非聚簇索引,如果没有则使用聚簇索引(主键)。而对于count(列名),如果当前列有索引,则能使用到索引,如果没有,则是全表扫描,使用不到索引。具体如下:

EXPLAIN
SELECT count(1)
from tb_user_info

1.无where条件,有聚簇索引的count(常量)、count(*),即走非聚簇索引
image
        如果没有索引,则是走的主键索引,如果加了索引,则使用加的非聚簇索引。如下图:

2.无where条件,无非聚簇索引的count(常量)、count( *),即走主键索引
image

       count列,如果count的列有索引则使用索引,否则是全表扫描,要过滤null值。

EXPLAIN
SELECT count(sex)
from tb_user_info

3.无where条件,count列有索引,即走索引
image

4.无where条件,count列无索引,即全表扫描
image

count后有where条件

       主要以where条件为主,如果跟的where后的条件有索引,则就使用索引,否则就是全表扫描。

EXPLAIN
SELECT count(*)
from tb_user_info
where sex = 1

1.有where条件,count(常量)、count(*)跟where条件后是否有索引有关,即where后有索引则用到索引,否则全表扫描。

EXPLAIN
SELECT count(sex)
from tb_user_info
where sex = 1

2.有where条件,count列 跟where条件后是否有索引有关,即where后有索引则用到索引,否则全表扫描。

结语

       可以看到的是count(常量)、count(*)在使用上是一样的,在没有where条件的情况下会使用索引,如果有where条件的话需要看where条件是否能使用到索引;而count(列名),则是跟列名是否建立索引有关。

推荐阅读