MySQL的COUNT()函数理解

标签(空格分隔): MySQL5.7 COUNT()函数 探讨


写在前面的话

细心的朋友会在平时工作和学习中,可以看到MySQL的COUNT()函数有多种不同的参数,从而会有不同的统计方式,本文正是出于此目的一探究竟。

主要内容&你能获得什么

辨析COUNT(*)、COUNT(1)、COUNT(0)、COUNT(列名)、COUNT(DISTINCT 列名)的区别和作用。

探讨

基本理解

COUNT()函数用来统计表的行数,也就是统计记录行数,很好理解。查看MySQL5.7官方手册

官方对COUNT(expr)解释:

Returns a count of the number of non-NULL values of expr in the rows retrieved by a SELECT statement. The result is a BIGINT value. If there are no matching rows, COUNT() returns 0.

COUNT(*) is somewhat different in that it returns a count of the number of rows retrieved, whether or not they contain NULL values.

COUNT(DISTINCT expr,[expr...])Returns a count of the number of rows with different non-NULL expr values.If there are no matching rows, COUNT(DISTINCT) returns 0.

在SELECT检索语句中,COUNT(expr)统计并返回参数expr为非NULL值的总行数,COUNT(DISTINCT expr)返回的是参数expr为非NULL值且不相同的总行数,结果是一个BIGINT数据类型的值,占8个字节;如果没有匹配到满足条件的行,结果返回0。但是当expr不是具体的列,是COUNT(*)时会统计表中所有的行数,即使某些行是NULL也会被统计在内

测试

新建测试表users

CREATE TABLE `users` (
`Id` int(11) NOT NULL AUTO_INCREMENT,
`LoginName` varchar(50) DEFAULT NULL,
`LoginPwd` varchar(16) DEFAULT NULL,
`Name` varchar(16) DEFAULT NULL,
`Address` varchar(16) DEFAULT NULL,
`Phone` varchar(16) DEFAULT NULL,
`Mail` varchar(16) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; #插入数据
mysql> select * from users;
+----+------------+----------+------+----------+-------------+---------------+
| Id | LoginName | LoginPwd | Name | Address | Phone | Mail |
+----+------------+----------+------+----------+-------------+---------------+
| 1 | bb1 | 123 | 张三 | 湖北武汉 | 13317190688 | 123@gmail.com |
| 2 | bb3 | 123 | 李四 | 湖北武汉 | 13317190688 | 123@gmail.com |
| 3 | jj4 | 123 | 张三 | 湖北武汉 | 13317190688 | 123@gmail.com |
| 4 | kobeBryant | 123456 | NULL | LA | NULL | NULL |
| 5 | kobe | 456 | NULL | NULL | NULL | NULL |
| 6 | Jay | NULL | NULL | GXI | NULL | NULL |
| 7 | jj4 | NULL | NULL | NULL | NULL | NULL |
+----+------------+----------+------+----------+-------------+---------------+
7 rows in set

执行查询

mysql> SELECT COUNT(*),COUNT(1),COUNT(0),COUNT(-1), COUNT(LoginPwd),COUNT(Phone),COUNT(DISTINCT Phone) FROM users;
+----------+----------+----------+-----------+-----------------+--------------+------------------------+
| COUNT(*) | COUNT(1) | COUNT(0) | COUNT(-1) | COUNT(LoginPwd) | COUNT(Phone) | COUNT(DISTINCT Phone) |
+----------+----------+----------+-----------+-----------------+--------------+------------------------+
| 7 | 7 | 7 | 7 | 5 | 3 | 1 |
+----------+----------+----------+-----------+-----------------+--------------+------------------------+
1 row in set

根据上述结果可以有以下结论:

  • COUNT(*)、COUNT(1)、COUNT(0)统计的是所有行数,结果都是7行。
  • COUNT(LoginPwd)、COUNT(Phone)分别统计列LoginPwd、列Phone的非NULL的行数,结果分别是5行、3行。
  • COUNT(DISTINCT Phone)只统计列Phone的非NULL且不相同的行数,结果是1行。

辨析

对 COUNT(LoginPwd)、COUNT(Phone)和COUNT(DISTINCT Phone)的结果我们不难理解,关键是要弄清楚COUNT(*)、COUNT(1)、COUNT(0)这三个式子,它们的使用区别是什么,或者是没区别。

查看官方文档:

For MyISAM tables, COUNT(*) is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause. 

This optimization only applies to MyISAM tables, because an exact row count is stored for this storage engine and can be accessed very quickly. COUNT(1) is only subject to the same optimization if the first column is defined as NOT NULL.

For transactional storage engines such as InnoDB, storing an exact row count is problematic because multiple transactions may be occurring, each of which may affect the count. 

  • 对于使用MyISAM存储引擎的每张表都会为了优化查询,会定义一个变量row count来记录目前表的总行数,我们可以快速获得一张表的总行数,但是想要快速拿到这个变量,查询的时候就要遵循一定的要求,即不能同时查询其他的列且不能有WHERE语句(如“SELECT COUNT(*) FROM student;”)。如果是使用COUNT(1),这个表的第一列要定义为非NULL才会拿到这个row count变量,否则就是全表扫描统计。
  • 对于事务型存储引擎,如InnoDB,使用COUNT(*)是全表扫描统计(如果有索引会根据索引优化查询)。如果有row count这样的一个变量,因为同一时间可能会有多个事务同时操作,可能会带来并发操作的问题,row count的结果会不一致,所以事务型引擎并没有优化COUNT(*)查询。

COUNT执行细节

  • 执行综合查询
mysql> explain SELECT COUNT(*),COUNT(1),COUNT(0),COUNT(-1), COUNT(LoginPwd),COUNT(Phone),COUNT( DISTINCT Phone) FROM users;
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
| 1 | SIMPLE | users | ALL | NULL | NULL | NULL | NULL | 7 | NULL |
+----+-------------+-------+------+---------------+------+---------+------+------+-------+
1 row in set

执行整条语句的时候,可以看到type字段是ALL,使用了全表扫描,表的行数是rows=7

  • 执行COUNT(*)
mysql> explain SELECT COUNT(*) FROM users;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | users | index | NULL | PRIMARY | 4 | NULL | 7 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set

执行COUNT(*)可以看到type字段是index,没有使用全表扫描,而是使用了索引优化查询,使用了主键PRIMARY索引,表的行数是rows=7

  • 执行COUNT(1)
mysql> explain SELECT COUNT(1) FROM users;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | users | index | NULL | PRIMARY | 4 | NULL | 7 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set

执行COUNT(1)可以看到type字段是index,没有使用全表扫描,而是使用了索引优化查询,使用了主键PRIMARY索引。

  • 执行COUNT(0)
mysql> explain SELECT COUNT(0) FROM users;
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
| 1 | SIMPLE | users | index | NULL | PRIMARY | 4 | NULL | 7 | Using index |
+----+-------------+-------+-------+---------------+---------+---------+------+------+-------------+
1 row in set

执行COUNT(0)可以看到type字段是index,没有使用全表扫描,而是使用了索引优化查询,使用了主键PRIMARY索引。

对于InnoDB,查询COUNT(*)和COUNT(1)二者并没有区别,性能效率等效,都是全表扫描(有索引则会优化自动使用索引)。

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

结论

|序号|类别|作用|解释说明|使用|

|---|---|---|---|

|1|COUNT(*)|统计总行数,含NULL值|MyISAM引擎,如果没有查询其他列且无WHERE语句会直接返回row count变量,高效。其他情况全表扫描(有索引则用索引),统计表的总行数。|如果仅仅是统计总行数,任何情况先推荐使用“SELECT COUNT(*) FROM 表名”。|

|2|COUNT(n)|统计总行数,可以是COUNT(任何整数或小数),含NULL值|如COUNT(1),MyISAM引擎如果没有查询其他列且无WHERE语句且第一列定义为非NULL会直接返回row count变量,高效。其他情况全表扫描(有索引则用索引)|表的第一列定义为非NULL,推荐使用“SELECT COUNT(1) FROM 表名”。|

|3|COUNT(列名)|统计某一列非NULL的行数|纯粹统计指定列的非NULL行数,不区分存储引擎|看业务需求|

|4|COUNT(DISTINCT 列名)|统计某一列非NULL且不相同的行数|纯粹统计指定列的非NULL且不相同的行数,不区分存储引擎|看业务需求|

使用选择:

  • COUNT(*)和COUNT(n)本质上一样,具体响应时间跟存储引擎和WHERE条件有关。个人习惯使用COUNT(1)。
  • 索引对COUNT()函数很重要,如果要用到索引,MySQL会自动优化使用合适的索引。
  • COUNT(列名)需要注意统计的是非NULL的列。

使用SUM(1)也可以达到统计表总行数的目的,而且也包含NULL值,但是效率没有COUNT(*)高。

参考:

https://highdb.com/了解-select-count-count1-和-countfield/

官方手册:https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html#function_count

MySQL的COUNT()函数理解的更多相关文章

  1. MySQL中count函数使用方法详解

      count函数是用来统计表中或数组中记录的一个函数,下面我来介绍在MySQL中count函数用法与性能比较吧. count(*) 它返回检索行的数目, 不论其是否包含 NULL值. SELECT ...

  2. NET MVC全局异常处理(一) 【转载】网站遭遇DDoS攻击怎么办 使用 HttpRequester 更方便的发起 HTTP 请求 C#文件流。 Url的Base64编码以及解码 C#计算字符串长度,汉字算两个字符 2019周笔记(2.18-2.23) Mysql语句中当前时间不能直接使用C#中的Date.Now传输 Mysql中Count函数的正确使用

    NET MVC全局异常处理(一)   目录 .NET MVC全局异常处理 IIS配置 静态错误页配置 .NET错误页配置 程序设置 全局异常配置 .NET MVC全局异常处理 一直知道有.NET有相关 ...

  3. MySQL中Count函数的参数该传入什么样的值?

    MySQL中Count函数的参数该传入什么样的值? 查询用户表中总记录 用户表中信息如下: 1.SELECT COUNT(*) FROM USER 结果为:3条 2.  SELECT COUNT(us ...

  4. Mysql中Count函数的正确使用

    备注: 直接使用Count(*)或Count(1)这些大家基本都会,主要是Count函数还可以加满足表达式的统计:express 关于Count函数表达式的用法,目前个人只知道2种: a:使用:Cou ...

  5. 在MySQL的InnoDB存储引擎中count(*)函数的优化

    写这篇文章之前已经看过了很多数据库方面的优化内容,大部分都是加索引.使用事务.要什么select什么等等.然而,只是停留在阅读的层面上,很少有实践,因为没有遇到真实的项目,一切都是纸上谈兵.实践是检验 ...

  6. Mysql与Sql server,Sum函数跟Count函数

    两者均是统计类函数,都不计算NULL字段!!! 单纯计算行数的话,count的效率比sum的效率高 MySQL SUM()函数介绍 SUM()函数用于计算一组值或表达式的总和,SUM()函数的语法如下 ...

  7. mysql count的理解

    mysql count的理解 1 select count(tel) as telcount from info;如果tel列有null 将不会被统计进去 2 count(*) 这样写性能更好 3 M ...

  8. mysql COUNT()函数 语法

    mysql COUNT()函数 语法 作用:返回匹配指定条件的行数.博智达直线电机平台 语法:SELECT COUNT(*) FROM table_name mysql COUNT()函数 示例 // ...

  9. MySQL中group_concat函数深入理解

    本文通过实例介绍了MySQL中的group_concat函数的使用方法,比如select group_concat(name) . 一.MySQL中group_concat函数 完整的语法如下: gr ...

随机推荐

  1. EZ 2018 04 13 NOIP2018 模拟赛(八)

    这次的题目都是什么鬼? 玄学乱搞+肉眼看CODE+倒着搜索? 好吧是我ZZ了 链接在此 T1 玄学乱搞 由于考场上写的部分分做法忘记讨论n<=2000时的情况,少得了30pts 很容易得到一个基 ...

  2. 编程语法分析之“优先级”和“结合律”

    上节<编程语法分析之从表达式说起>中说到表达式,他的主要作用就是返回一个值!那这个值具体是多少,就要看表达式的整个运算过程.要理解表达式的运算过程就必须了解"优先级"和 ...

  3. Keras实现风格迁移

    风格迁移 风格迁移算法经历多次定义和更新,现在应用在许多智能手机APP上. 风格迁移在保留目标图片内容的基础上,将图片风格引用在目标图片上. 风格本质上是指在各种空间尺度上图像中的纹理,颜色和视觉图案 ...

  4. cocos2d-x学习记录2——CCAction动作

    CCAction能够使CCNode运动起来,能够呈现出多种多样的动作.这些动作能够改变其运动方向.形状.大小.旋转等. 同时,还可利用CCCallFunc.CCCallFuncN.CCCallFunc ...

  5. ASP.NET多行文本框限制字符个数

    asp.net中TextBox当设置TextMode = Multiline时,其MaxLength属性无效.可使用JS进行辅助限制输入的字符个数.中文算两个字符,西文算1个字符. TextBox属性 ...

  6. 联想拯救者15-isk安装固态硬盘与系统迁移教程

    一.固态选择 首先知道拯救者15-ISK是m.2接口2280尺寸,支持PCIE协议NVMe接口标准.我加装的固态是HP EX900系列250G M.2 NVMe固态硬盘. 二.开盖安装 1.拯救者15 ...

  7. linux下SpringBoot Jar包自启脚本配置

    今天整理服务器上SpringBoot项目发现是自启的,于是想看看实现.翻看离职同事的交接文档发现一个***.service文件内容如下 [Unit] Description=sgfront After ...

  8. torchvision 批量可视化图片

    1.1 简介 计算机视觉中,我们需要观察我们的神经网络输出是否合理.因此就需要进行可视化的操作. orchvision是独立于pytorch的关于图像操作的一些方便工具库. torchvision的详 ...

  9. win10系统安装web3js的正确方法

    在安装web3的时候 用npm  install web3 –save-dev 在win10系统下会一直安装不成功.后来换用了 cnpm install web3 –save-dev 安装时候报出:C ...

  10. PAT甲题题解-1055. The World's Richest (25)-终于遇见一个排序的不水题

    题目简单,但解题的思路需要转换一下,按常规思路肯定超时,推荐~ 题意:给出n个人的姓名.年龄和拥有的钱,然后进行k次查询,输出年龄在[amin,amx]内的前m个最富有的人的信息.如果财富值相同就就先 ...