网站地图页面模板,昆明市城市基本建设档案馆网站,北京市住房建设投资中心网站,wordpress.org密码【MySQL】- 09 Select Count 1认识COUNT2 COUNT(列名)、COUNT(常量)和COUNT(*)之间的区别3 COUNT(*)的优化 4 COUNT(*)和COUNT(1)5 COUNT(字段)总结 数据库查询相信很多人都不陌生#xff0c;所有经常有人调侃程序员就是CRUD专员#xff0c;这所谓的CRUD指的就是数据库的增删… 【MySQL】- 09 Select Count 1认识COUNT2 COUNT(列名)、COUNT(常量)和COUNT(*)之间的区别3 COUNT(*)的优化 4 COUNT(*)和COUNT(1)5 COUNT(字段)总结 数据库查询相信很多人都不陌生所有经常有人调侃程序员就是CRUD专员这所谓的CRUD指的就是数据库的增删改查。 在数据库的增删改查操作中使用最频繁的就是查询操作。而在所有查询操作中统计数量操作更是经常被用到。 关于数据库中行数统计无论是MySQL还是Oracle都有一个函数可以使用那就是COUNT。 但是就是这个常用的COUNT函数却暗藏着很多玄机尤其是在面试的时候一不小心就会被虐。不信的话请尝试回答下以下问题
COUNT有几种用法COUNT(字段名)和COUNT()的查询结果有什么不同COUNT(1)和COUNT()之间有什么不同COUNT(1)和COUNT()之间的效率哪个更高为什么《阿里巴巴Java开发手册》建议使用COUNT()MySQL的MyISAM引擎对COUNT()做了哪些优化MySQL的InnoDB引擎对COUNT()做了哪些优化上面提到的MySQL对COUNT()做的优化有一个关键的前提是什么SELECT COUNT() 的时候加不加where条件有差别吗COUNT(*)、COUNT(1)和COUNT(字段名)的执行过程是怎样的
以上10道题如果您可以全部准确无误的回答的话那说明你真的很了解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*是SQL92定义的标准统计行数的语法跟数据库无关跟NULL和非NULL无关。 说明count*会统计值为NULL的行而count列名不回统计此列为NULL值的行。 2 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以及数据库的行为事务、隔离级别等。
3 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条件。 4 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中的这个问题也是众说纷纭的呢。
5 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(*)查询表的行数