在数据库的增删改查操作中,使用最频繁的就是查询操作。而在所有查询操作中,统计数量操作更是经常被用到。
关于数据库中行数统计,无论是MySQL还是Oracle,都有一个函数可以使用,那就是COUNT
。
COUNT
MySQL官网给出的解释是:
1、COUNT(expr) ,返回SELECT语句检索的行中expr的值不为NULL的数量。结果是一个BIGINT值。
2、如果查询结果没有命中任何记录,则返回0
3、但是,值得注意的是,COUNT(*)
的统计结果中,会包含值为NULL的行数。
例如:
代码语言:javascript复制create table #bla(id int,age int)
insert #student values(null,null)
insert #student values(1,null)
insert #student values(null,1)
insert #student values(1,null)
insert #student values(null,1)
insert #student values(1,null)
insert #student values(null,null)
使用语句count(*),count(id),count(id2)查询结果如下:
代码语言:javascript复制select count(*),count(id),count(age)
from #student
results 7 3 2
COUNT(常量)
和 COUNT(*)
表示的是直接查询符合条件的数据库表的行数。而COUNT(列名)
表示的是查询符合条件的列的值不为NULL的行数。
而COUNT(*)是SQL92定义的标准统计行数的语法,因为他是标准语法,所以MySQL数据库对他进行过很多优化。
SQL92,是数据库的一个ANSI/ISO标准。它定义了一种语言(SQL)以及数据库的行为(事务、隔离级别等)。
COUNT(*)的优化
区分不同的执行引擎,MySQL中比较常用的执行引擎就是InnoDB和MyISAM。
MyISAM和InnoDB有很多区别,其中有一个关键的区别和我们接下来要介绍的COUNT(*)有关,那就是MyISAM不支持事务,MyISAM中的锁是表级锁;而InnoDB支持事务,并且支持行级锁。
MyISAM
做了一个简单的优化,那就是它可以把表的总行数单独记录下来,如果从一张表中使用COUNT(*)进行查询的时候,可以直接返回这个记录下来的数值就可以了,当然,前提是不能有where条件。
InnoDB
中索引分为聚簇索引(主键索引)和非聚簇索引(非主键索引),聚簇索引的叶子节点中保存的是整行记录,而非聚簇索引的叶子节点中保存的是该行记录的主键的值。
所以,相比之下,非聚簇索引要比聚簇索引小很多,所以MySQL会优先选择最小的非聚簇索引来扫表。所以,当我们建表的时候,除了主键索引以外,创建一个非主键索引还是有必要的。
至此,我们介绍完了MySQL数据库对于COUNT(*)的优化,这些优化的前提都是查询语句中不包含WHERE以及GROUP BY条件。
COUNT(1)
InnoDB handles SELECT COUNT(*) and SELECT COUNT(1) operations in the same way. There is no performance difference.
所以,对于COUNT(1)和COUNT(*),MySQL的优化是完全一样的,根本不存在谁比谁快!
建议使用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()查询表的行数!
Q.E.D.