首页 > 其他分享 >count(*) count(1) count(字段)效率问题

count(*) count(1) count(字段)效率问题

时间:2023-04-12 21:14:40浏览次数:37  
标签:count COUNT 查询 问题 InnoDB 行数 MySQL 效率

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

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

你知道答案吗?很多人都认为COUNT(1)比COUNT(*)效率高,真的是这样吗?

1、认识COUNT

关于COUNT函数,在MySQL官网中有详细介绍:

 

 

简单翻译一下:

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 tbl_name语句,确实在扫表的过程中做了一些优化。前提是查询语句中不包含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(*)查询表的行数!
————————————————
版权声明:本文为CSDN博主「yz_wlkj」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/pyzfirst/article/details/108521334

 

标签:count,COUNT,查询,问题,InnoDB,行数,MySQL,效率
From: https://www.cnblogs.com/gmh1/p/17311238.html

相关文章

  • 百鸡百钱问题
    一、问题描述:一只公鸡五钱,一只母鸡三钱,现在用百钱买百鸡,问公鸡,母鸡,小鸡各多少钱?二、设计思路:直接利用三层循环暴力解除完事,条件判断联立两个等式三、程序流程图:四、代码实现:#include<iostream>代码一:三层循环,效率有点低using namespace std;int main(){    i......
  • 一个朋友问的排序问题,Collections.sort
    importjava.util.ArrayList;importjava.util.Collections;importjava.util.List;publicclassMySortimplementsComparable<MySort>{privateStringname;privateintage;publicMySort(){super();}publicMySort(Stringname,in......
  • 百钱百鸡问题
    一、问题描述:中国古代数学家张丘建在他的《算经》中提出以一个著名的“百钱百鸡问题”:一只公鸡值五钱,一只母鸡值三钱,三只小鸡值一钱,现在要用百钱买百鸡,请问公鸡、母鸡、小鸡各多少只?二、设计思路:1、定义公鸡cook,母鸡hen,小鸡的chicken。根据钱只有100及只买一百只鸡可得公鸡最多......
  • 关于浏览器sessionStorage共享问题
    今天也是闲暇之余看了点前端基础知识发现了好玩的window.open("同源页面")这种方式新开的页面会复制之前的sessionStorage通过a标签新开的页面同样也会,原理相同,在这就不赘述了。SessionStorage也有同源策略的限制,但是SessionStorage有一条更加严格的限制SessionStorage只有在......
  • 扩容及迭代器失效问题
    vector扩容问题vector在尾部插入(push_back)时的扩容voidtest3(){vector<int>num={1,2,3,4,5};cout<<"num.size()="<<num.size()<<endl;cout<<"num.capacity()="<<num.capacity()<<e......
  • 关于百鸡百钱问题的C语言解决
    百鸡百钱问题 1.问题描述公鸡5钱一只,母鸡3钱一只,小鸡1钱三只,用一百个钱买一百只鸡,公鸡,母鸡,小鸡各多少只2.设计思路不妨先设公鸡数量为x母鸡数量为y小鸡数量为z则可列出方程:x+y+z=1005x+3y+1/3z=100又因为只有100钱所以x<20y<333.程序流程 4.代码#include<stdio.h>......
  • 呼叫中心运营管理问题怎样解决?
    在当今这个以服务取胜的时代,各行业都在积极利用呼叫中心来提高客户服务质量,降低业务成本。随着客服队伍的不断壮大,呼叫中心运营管理时普遍存在下列问题:1.客服人员流动性大,培训周期长,客服能力参差不齐,服务标准不统一。当遇到负面情绪时,很容易影响工作效率,会导致人员变相流失,增加企......
  • 针对form 表单 只有一个输入框的时候 使用回车查询会刷新页面问题
    <el-form:model="queryParams"ref="queryForm" :inline="true"v-show="showSearch"label-width="68px"@submit.native.prevent>   <el-form-itemlabel="表单名"prop="name">......
  • (三)python多进程multiprocessing模块的变量传递问题:父进程中的numpy.array对象隐式序列
    参考:https://docs.python.org/zh-cn/3/library/multiprocessing.htmlcloudpickle——Python分布式序列化的专用模块python多进程multiprocessing模块的变量传递问题:父进程中的numpy.array对象隐式序列化到子进程后的inplace操作的问题-Death_Knight-博客园(cnblogs.com)......
  • 百钱百鸡问题
    一、问题描述一只公鸡值五钱,一只母鸡值三钱,三只小鸡值一钱,现在要用百钱买百鸡,请问公鸡,母鸡,小鸡各多少只?二、设计思路1、公鸡只数小于20,母鸡只数小于33,小鸡数量小于一百2、分别设出公鸡,母鸡,小鸡的初始值为零,利用循环进行数量的递增,令三者数量和为100,所花钱数为100三、程序流程......