count(*) count(1)与count(字段)的区别

53fe20266ffc413a86c3b9abc9642dab.png

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

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

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

那么问题来了count(*) 、count(1) 、count(字段)用哪个?
最新版的阿里巴巴开发手册:


df2131ea004d4a68b41c3c5a1de39d59.png

SQL92,是数据库的一个ANSI/ISO标准。它定义了一种语言(SQL)以及数据库的行为(事务、隔离级别等)
另外:


5890444fd0cb421fbeea6c4397d129e9.png

说了啥?
1.对于存储引擎 InnoDB,存储精确的行数是有问题的。多个事务可能同时发生,每个事务都可能影响计数。

2。InnoDB不保留表中行的内部计数,因为并发事务可能同时 “看到”不同数量的行。因此,SELECT COUNT(*) 语句只计算对当前事务可见的行。

3.从 MySQL 8.0.13 开始,如果没有额外的子句(如或 ) ,则表的查询性能针对单线程工作负载进行了优化。 SELECT COUNT(*) FROM tbl_nameInnoDBWHEREGROUP BY

4.InnoDBSELECT COUNT()通过遍历最小的可用二级索引来处理语句,除非索引或优化器提示指示优化器使用不同的索引。如果二级索引不存在,则通过扫描聚集索引来InnoDB 处理SELECT COUNT()语句。

5.SELECT COUNT()如果索引记录不完全在缓冲池中,则 处理语句需要一些时间。为了更快地计数,创建一个计数器表并让您的应用程序根据它所做的插入和删除来更新它。但是,在数千个并发事务启动对同一计数器表的更新的情况下,此方法可能无法很好地扩展。如果近似行数就足够了,请使用 SHOW TABLE STATUS。
6.InnoDB处理SELECT COUNT(
)和SELECT COUNT(1) 操作方式相同。没有性能差异。
特别重点,官方文档说的:

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

没有啥区别!
接下来,给出区别及分析

一、执行结果
count(*) 和count(1) 都是统计行数,而count(字段) 是统计字段列非null的行数

二、不同的存储引擎
在不同的存储引擎中,count(*)函数的执行是不同的

MyISAM和InnoDB有很多区别,其中有一个关键的区别和我们接下来要介绍的COUNT(*)有关,那就是MyISAM不支持事务,MyISAM中的锁是表级锁;而InnoDB支持事务,并且支持行级锁。

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

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

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

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

InnoDB:
在InnoDB存储引擎中,count(*)函数是先从内存中读取表中的数据到内存缓冲区,然后扫描全表获得行记录数。在使用count函数中加上where条件时,在两个存储引擎中的效果是一样的,都会扫描全表计算某字段有值项的次数。

说点官话:mysql对于count(*) 的优化

InnoDB 是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值。所以,普通索引树比主键索引树小很多。对于 count() 这样的操作,遍历哪个索引树得到的结果逻辑上都是一样的。因此,MySQL 优化器会找到最小的那棵树来遍历。因此表有二级索引,则使用二级索引key_len最小的索引进行扫描,尽管这个二级索引的key_len的值大于主键,都使用二级索引。在保证逻辑正确的前提下,尽量减少扫描的数据量,是数据库系统设计的通用法则之一。

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

从MySQL 8.0.13开始,针对InnoDB的SELECT COUNT(*) FROM tbl_name语句,确实在扫表的过程中做了一些优化。前提是查询语句中不包含WHERE或GROUP BY等条件。

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

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

所以,相比之下,非聚簇索引要比聚簇索引小很多,所以MySQL会优先选择最小的非聚簇索引来扫表。所以,当我们建表的时候,除了主键索引以外,创建一个非主键索引还是有必要的。

count(字段)

1、如果这个字段定义为not null的话,一行行地从记录里面读出这个字段,判断不能为null,按行累计加1

2、如果这个字段定义允许为null,一行行地从记录里面读出这个字段,执行的时候还要判断是否为null,不为null的按行累计加1,返回累加值

三、执行效率
1、如果在开发中需要用到count()聚合,那么优先考虑count(),因为mysql本身对于count()做了特别的优化处理。

有主键或联合主键的情况下,count()略比count(1)快一些。
没有主键的情况下count(1)比count(
)快一些。
如果表只有一个字段,则count(*)是最快的。

2、使用count()聚合函数后,最好不要跟where age = 1;这样的条件,会导致不走索引,降低查询效率。除非该字段已经建立了索引。使用count()聚合函数后,若有where条件,且where条件的字段未建立索引,则查询不会走索引,直接扫描了全表。

3、count(字段),非主键字段,这样的使用方式最好不要出现,因为它不会走索引。

count(主键ID)比count(1)慢的原因?
对于 count(主键 ID) 来说,InnoDB 引擎会遍历主键索引树,把每一行的ID值取出来,返回给server层,server层拿到ID后,判断是不可能为空的,按行累加加1,最后返回累计值。

对于count(1),InnoDB引擎会扫描主键索引树,但不取值,server层对于返回的每一行,按行累计加1,判断不可能为NULL,返回累计值。

从InnoDB引擎层返回ID会涉及到解析数据行、拷贝字段值的操作,因此count(主键 ID)执行要比count(1)执行慢。

count(主键id)走主键索引的时候效率较count(*)差的原因?
平时我们检索一列的时候,基本上等值或范围查询,那么索引基数大的索引必然效率很高(符合走主键索引查找速度最快的原则)。

但是在做count(*)的时候并没有检索具体的一行或者一个范围,那么选择基数小的索引对count操作效率会更高。在做count操作的时候,mysql会遍历每个叶子节点,所以基数越小,效率越高。mysql非聚簇索引叶子节点保存指向主键ID的指针,所以需要检索两遍索引。但是这里相对于遍历主键索引,即使检索两遍索引效率也比单纯的检索主键索引快。

Innodb是索引组织表,主键索引树的叶子节点是数据,而普通索引树的叶子节点是主键值,所以普通索引树小很多,索引长度越小树的大小就越小。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容