在数据库的增删改查操作中,使用最频繁的就是查询操作。

而在所有查询操作中,统计数量操作更是经常被用到。

关于数据库中行数统计,无论是MySQL还是Oracle亦或者是SqlServer,都有一个函数可以使用,那就是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(字段名)的执行过程是怎样的?

如果以上10道题,全部准确无误的回答的话,那说明你真的很了解COUNT函数了,如果有哪些知识点是不了解的,那么本文正好可以重新帮你认识一下Count,也为数据库优化做一些思考。

认识COUNT

关于COUNT函数的介绍:

1、COUNT(expr) ,返回SELECT语句检索的行中expr的值不为NULL的数量。结果是一个BIGINT值。

2、如果查询结果没有命中任何记录,则返回0

3、但是,值得注意的是,COUNT() 的统计结果中,会包含值为NULL的行数。

例:

create table #bla(id int,id2 int)
insert #bla values(null,null)
insert #bla values(1,null)
insert #bla values(null,1)
insert #bla values(1,null)
insert #bla values(null,1)
insert #bla values(1,null)
insert #bla values(null,null)

使用语句count(),count(id),count(id2)查询结果如下:

select count(),count(id),count(id2)
from #bla
results 7 3 2

除了COUNT(id)和COUNT()以外,还可以使用COUNT(常量)(如COUNT(1))来统计行数,那么这三条SQL语句有什么区别呢?

到底哪种效率更高呢?

为什么《阿里巴巴Java开发手册》中强制要求不让使用 COUNT(列名)或 COUNT(常量)来替代COUNT()呢?

COUNT(列名)、COUNT(常量)和COUNT()之间的区别

前面我们提到过COUNT(expr)用于做行数统计,统计的是expr不为NULL的行数,那么COUNT(列名)、 COUNT(常量) 和 COUNT()这三种语法中,expr分别是列名、 常量 和 。

那么列名、 常量 和 这三个条件中,常量是一个固定值,肯定不为NULL。

可以理解为查询整行,所以肯定也不为NULL,那么就只有列名的查询结果有可能是NULL了。

所以, COUNT(常量) 和 COUNT()表示的是直接查询符合条件的数据库表的行数。

而COUNT(列名)表示的是查询符合条件的列的值不为NULL的行数。

除了查询得到结果集有区别之外,COUNT()相比COUNT(常量) 和 COUNT(列名)来讲,COUNT()是SQL92定义的标准统计行数的语法,因为他是标准语法,所以MySQL数据库对他进行过很多优化。

SQL92,是数据库的一个ANSI/ISO标准。

它定义了一种语言(SQL)以及数据库的行为(事务、隔离级别等)。

COUNT()的优化

前面提到了COUNT()是SQL92定义的标准统计行数的语法,所以MySQL数据库对他进行过很多优化。

那么,具体都做过哪些事情呢?

这里的介绍要区分不同的执行引擎。

MySQL中比较常用的执行引擎就是InnoDB和MyISAM。MyISAM和InnoDB有很多区别,其中有一个关键的区别和我们接下来要介绍的COUNT()有关,那就是MyISAM不支持事务,MyISAM中的锁是表级锁;

而InnoDB支持事务,并且支持行级锁。

因为MyISAM的锁是表级锁,所以同一张表上面的操作需要串行进行,所以,MyISAM做了一个简单的优化,那就是它可以把表的总行数单独记录下来,如果从一张表中使用COUNT()进行查询的时候,可以直接返回这个记录下来的数值就可以了,当然,前提是不能有where条件。

MyISAM之所以可以把表中的总行数记录下来供COUNT()查询使用,那是因为MyISAM数据库是表级锁,不会有并发的数据库行数修改,所以查询得到的行数是准确的。

但是,对于InnoDB来说,就不能做这种缓存操作了,因为InnoDB支持事务,其中大部分操作都是行级锁,所以可能表的行数可能会被并发修改,那么缓存记录下来的总行数就不准确了。

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

在InnoDB中,使用COUNT()查询行数的时候,不可避免的要进行扫表了,那么,就可以在扫表过程中下功夫来优化效率了。

从MySQL 8.0.13开始,针对InnoDB的SELECT COUNT() FROM tblname语句,确实在扫表的过程中做了一些优化。

前提是查询语句中不包含WHERE或GROUP BY等条件。

我们知道,COUNT()的目的只是为了统计总行数,所以,他根本不关心自己查到的具体值,他如果能够在扫表的过程中,选择一个成本较低的索引进行的话,那就可以大大节省时间。

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

所以,相比之下,非聚簇索引要比聚簇索引小很多,所以MySQL会优先选择最小的非聚簇索引来扫表。

当我们建表的时候,除了主键索引以外,创建一个非主键索引还是有必要的。

至此,我们介绍完了MySQL数据库对于COUNT()的优化,这些优化的前提都是查询语句中不包含WHERE以及GROUP BY条件。

COUNT()和COUNT(1)

介绍完了COUNT(),接下来看看COUNT(1),对于,这二者到底有没有区别,网上的说法众说纷纭。

有的说COUNT()执行时会转换成COUNT(1),所以COUNT(1)少了转换步骤,所以更快。

还有的说,因为MySQL针对COUNT()做了特殊优化,所以COUNT()更快。

那么,到底哪种说法是对的呢?

看下MySQL官方文档是怎么说的:

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

画重点:

same way , no performance difference。

所以,对于COUNT(1)和COUNT(),MySQL的优化是完全一样的,根本不存在谁比谁快!

那既然COUNT()和COUNT(1)一样,建议用哪个呢?

建议使用COUNT()!

因为这个是SQL92定义的标准统计行数的语法,而且本文只是基于MySQL做了分析,关于Oracle中的这个问题,也是众说纷纭的呢。

COUNT(字段)

最后,就是我们一直还没提到的COUNT(字段),他的查询就比较简单粗暴了,就是进行全表扫描,然后判断指定字段的值是不是为NULL,不为NULL则累加。相比COUNT(),COUNT(字段)多了一个步骤就是判断所查询的字段是否为NULL,所以他的性能要比COUNT()慢。

总结

本文介绍了COUNT函数的用法,主要用于统计表行数。

主要用法有COUNT()、COUNT(字段)和COUNT(1)。

因为COUNT()是SQL92定义的标准统计行数的语法,所以MySQL对他进行了很多优化,MyISAM中会直接把表的总行数单独记录下来供COUNT()查询,而InnoDB则会在扫表的时候选择最小的索引来降低成本。当然,这些优化的前提都是没有进行where和group的条件查询。

在InnoDB中COUNT()和COUNT(1)实现上没有区别,而且效率一样,但是COUNT(字段)需要进行字段的非NULL判断,所以效率会低一些。

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

本文来自木庄网络博客> 重新认识MySQL中的COUNT语句

重新认识MySQL中的COUNT语句的更多相关文章

  1. 用count(*)还是count(列名) || Mysql中的count()与sum()区别

    Mysql中的count()与sum()区别   首先创建个表说明问题 CREATE TABLE `result` (   `name` varchar(20) default NULL,   `su ...

  2. mysql中常用的语句整理

    mysql中常用的语句: 1:创建带自增长的主键的表 DROP TABLE IF EXISTS user_login ; CREATE TABLE user_login (   user_id INT ...

  3. Mysql中的条件语句if、case

    Mysql中的条件语句在我们对数据进行转换的时候比较有用,这样就不需要创建中转表. IF 函数 IF(expr1,expr2,expr3) 如果 expr1 是TRUE (expr1 <> ...

  4. MySQL中执行sql语句错误 Error Code: 1093. You can't specify target table 'car' for update in FROM clause

    MySQL中执行sql语句错误 Error Code: 1093. You can't specify target table 'car' for update in FROM clause 201 ...

  5. 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载

    浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...

  6. 在MySQL中阻止UPDATE语句没有添加WHERE条件的发生

    如果在生产环境中使用UPDATE语句更新表数据,此时如果忘记携带本应该添加的WHERE条件,那么..Oh,no…后果可能不堪设想.那么有没有什么办法可以阻止这样的事情发生,又不使用任何的审核工具呢.. ...

  7. mysql中的count(primary_key)、count(1)、count(*)的区别

    表结构如下: mysql> show create table user\G; *************************** 1. row ********************** ...

  8. mysql中,执行delete语句时出现Lock wait timeout exceeded问题

    问题描述: 当我插入一条记录时,在调用save方法的时候出现了异常(记录重复了),导致了后面的commit语句不能执行了.这时我在数据库中删除重复记录时发现该表已经被锁上了.即出现错误.但过了一会再次 ...

  9. MySQL中的replace语句

    一.背景 当使用replace语句更新access_apps表时,原有的mark列.remark列的信息丢失. CREATE TABLE `access_apps` (   `base` varcha ...

随机推荐

  1. ibatis 学习

    1.$与#的区别: 用到#和$来获取传的参数值,其中#是将传来的值替换(如果是字符串,会将‘’带着替换,比如上面$value$,用#value#的话,就会出错.#与$的使用区别:$中间的变量就是直接替 ...

  2. HttpClient连接池的一些思考

    前言 使用apache的httpclient进行http的交互处理已经很长时间了,而httpclient实例则使用了http连接池,想必大家也没有关心过连接池的管理.事实上,通过分析httpclien ...

  3. 关于CSS的书写规范和顺序

    关于CSS的书写规范和顺序,是大部分前端er都必须要攻克的一门关卡,如果没有按照良好的CSS书写规范来写CSS代码,会影响代码的阅读体验.这里总结了一个CSS书写规范.CSS书写顺序供大家参考,这些是 ...

  4. git一步步上传自己的项目至github,及仓库更新

    一.使用git上传项目到github 首先登陆github账号,选择新建一个库,填写项目名称,描述 创建完成之后,跳转到下面的页面,下面红框中的网址要记住,在后面上传代码的时候需要使用 接下来,我们需 ...

  5. k8s中负载均衡器【ingress-nginx】部署

    在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的.为了使外部的应用能够访问集群内的服务,在Kubernetes 目前 提供了以下几种方案: Node ...

  6. Python 爬虫从入门到进阶之路(十)

    之前的文章我们介绍了一下 Python 中正则表达式和 re 模块来做一个案例,爬取<糗事百科>的糗事并存储到本地.本章我们来看一下另一种爬取数据的方式 XPath. 我们在前面爬取< ...

  7. 02-16 k近邻算法

    目录 k近邻算法 一.k近邻算法学习目标 二.k近邻算法引入 三.k近邻算法详解 3.1 k近邻算法三要素 3.1.1 k值的选择 3.1.2 最近邻算法 3.1.3 距离度量的方式 3.1.4 分类 ...

  8. 02-28 scikit-learn库之线朴素贝叶斯

    目录 scikit-learn库之朴素贝叶斯 一.MultinomialNB 1.1 使用场景 1.2 代码 1.3 参数详解 1.4 属性 1.5 方法 二.GaussianNB 三.Bernoul ...

  9. 前端css杂记

    1em等于16px,页面默认是16px,一个字宽高都等于16px; 当行内元素display:inline的元素设置float:left浮动后,display值也被设置成block;总结:无论行内元素 ...

  10. 移动端自动化测试Appium 从入门到项目实战Python版☝☝☝

    移动端自动化测试Appium 从入门到项目实战Python版 (一个人学习或许会很枯燥,但是寻找更多志同道合的朋友一起,学习将会变得更加有意义✌✌)  说到APP自动化测试,Appium可是说是非常流 ...