mysql的count函数类型是什么意思_MySQL中的COUNT函数,你理解多少

前言:COUNT函数相比大家都不陌生,接触过数据库的兄弟们想必都用过,但是,就是这个常用的COUNT函数,却暗含许多玄机。

1、COUNT简介

看看官网对COUNT的简介

94065de9b3bd91d753e93bd20d0a9eda.png

大致意思是:COUNT(expr)返回SELECT语句中expr值不为NULL的行数,返回的结果类型为BIGINT;当没有匹配的行时,返回0;SELECT(*)将返回包括NULL值的行数。

2、COUNT函数常用的几种用法

COUNT(常量),COUNT(*),COUNT(字段),那么他们之间都有什么区别。

实际上,从前面的简介中就可以看出,COUNT(字段)和COUNT(*)的区别,COUNT(字段)返回的行数是不包括该字段为NULL的字段的,而COUNT(*)返回的行数其实就是实际查询结果的总行数,那么我们再看看COUNT(常量),举个例子,例如COUNT(1),1肯定不为NULL,那么根据MySQL COUNT(expr)的简介,返回expr值不为NULL的行数,那么其实COUNT(常量)返回的也是实际查询结果的总行数。

下面我们建个表简单测试一下:

create table count_test(col1 varchar(1),col2 varchar(1));

insert into count_test value ('1','1');

insert into count_test value ('1',null);

insert into count_test value (null,'1');

insert into count_test value ('1','1');

insert into count_test value (null,'1');

insert into count_test value ('1','1');

select COUNT(1),COUNT(*),COUNT(col1),COUNT(col2) from count_test;

a991fcadfc16a8f320cf18e5588ce711.png

3、COUNT(*)和COUNT(1)到底该怎么选择

如果有看过阿里的开发手册,就会知道阿里强制要求开发人员使用COUNT(*)进行数据统计,而非是COUNT(1),到底是为什么呢?

在SQL92中,COUNT(*)是标准的统计行数的语法,而作为标准语法,MySQL本身其实是对COUNT(*)做了很多优化的,那么我们接下来看看MySQL对COUNT(*)做了哪些优化。

MySQL对COUNT(*)其实在不同的存储引擎中是不同的,那么我们主要看看两种常用的存储引擎MyISAM和InnoDB。

首先我们简单看看MyISAM和InnoDB的区别。MyISAM不支持事务,并且使用的是表锁;InnoDB支持事务,并且支持行锁。

接下来我们看看到底做了什么优化:

MyISAM:前面我们说到,MyISAM使用的是表锁,所以我们在进行读操作时,并不需要担心会有写操作对这张表进行修改,从而影响表中行数,在这样的前提下,MyISAM做了一个简单的优化,那就是单独把表中总行数单独记录下来,在使用SELECT COUNT(*)进行查询时,直接返回这个记录下来的数值就可以,当然有一个前提就是不能带where条件。

InnoDB:说完MyISAM中的优化,我们再来看看InnoDB,首先InnoDB是支持行级锁的,那么就不能像MyISAM那样将行数缓存下来,因为在进行COUNT(*)查询时是有可能有写操作对行数产生影响的。那么InnoDB到底是怎么优化COUNT(*)的呢?我们都知道,COUNT(*)实际上是要进行全表扫描的,那不可避免的就要使用索引,而COUNT(*)并不关心获取的数据各字段的字段的值,那么在使用COUNT(*)进行查询的时候,MySQL会尽量选择一个成本最小的索引进行全表扫描。那么这里就不得不说一下聚簇索引和非聚簇索引了。

在说聚簇索引和非聚簇索引之前,我们先简单的说一下,使用InnoDB存储引擎,实际上索引和数据是存在同一个文件下的(*.idb),然后表中数据是存在索引的叶子节点的(这里不理解的可以先学习一下索引和B+树),那么但有多个索引时,总不能每个索引的叶子节点都存一份完整的数据,这样不仅浪费磁盘空间,同时也为造成查询IO的瓶颈问题。这时候就有了聚簇索引和非聚簇索引。

聚簇索引:根据上面说的,不可能每一个索引的叶子结点都存一份完整的数据,只需要其中一个索引的叶子结点存一份完整的数据即可,而这个索引就是聚簇索引,默认是主键索引,如果没有主键,会找第一个非空的唯一索引,如果还是没找到,就会以rowid创建一个索引作为聚簇索引。

非聚簇索引:那么什么是非聚簇索引呢,前面说到不可能每个索引的叶子结点都存一份完整的数据,那除了聚簇索引,其他索引的叶子结点应该存什么数据呢。其实这些索引的叶子节点存的是数据id值,也就聚簇索引节点中存的key值,而这些索引就是非聚簇索引。

那么回到前面的InnoDB对COUNT(*)的优化,MySQL会尽量选择一个成本最小的索引进行全表扫描,显然扫描非聚簇索引索引的成本是远远小于扫描聚簇索引的,而MySQL会选择一个成本最小的非聚簇索引进行全表扫描,这么说来,其实创建一个非主键索引也是非常必要的。当然这些都是在查询语句不包含where、group by等的前提下。

那么,有的人会说了,难道MySQL只对COUNT(*)做了优化,对COUNT(1)没有做优化吗?我们看看MySQL官方是怎么说。

InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.

大意是说:对于COUNT(1)和COUNT(*),MySQL的优化是完全一样的,根本不存在谁比谁快!

那么既然COUNT(1)和COUNT(*)优化一致,而COUNT(*)又是SQL92定义的标准统计语法,那么为啥不用COUNT(*)呢?

4、总结

本文简单介绍了MySQL中COUNT(字段),COUNT(常量),COUNT(*)之间的区别,相对于COUNT(字段),COUNT(常量)和COUNT(*)的效率更高,并且查询的结果是实际的总行数(包括NULL),而COUNT(*)又是SQL92定义的标准语法,所以在日常工作中推荐使用COUNT(*)进行行统计。

不知道大家有没有发现,本文中关于MySQL对COUNT(*)的优化都有一个前提,那就是查询语句不能包括where、group by,那么在有where的条件下,MySQL又是如何对COUNT(*)进行优化的呢,这个留作一个问题,在下篇文章中进行分析。

--------------------------------------------------------------------------------------------

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值