count()是SQL中一个常用的聚合函数,其被用来统计记录的总数,下面通过几个示例来说明此类查询的注意事项及应用技巧。
文章目录
- 一、count()的含义
- 二、count()的应用技巧
- 2.1 同时统计多列
- 2.2 利用执行计划
一、count()的含义
count()用于统计符合条件的记录总数,但其有2种用法:count(*)和count(column)
- count(*) 统计记录的总数
- count(column) 统计column列不为空的记录总数
这里的概念可能和部分人的理解有些偏差,在SQL中“*”通常代表所有列,SQL会通过查询数据字典来将其解析为所有列名,而count(*)并不会这样做,它会是直接统计数量。而count(column)只有在column列不为空的情况下才与count(*)的查询结果相同,因此如果你想统计总记录数,那么直接使用count(*),count(column)的结果可能会与你想的不同。
示例:count(*)和count(column)的区别
create table test(
id int primary key auto_increment,
name varchar(32)
);
insert into test values(null, 'Vincent'), (null, null);
select * from test;
表中共2条记录,其中id为2的name是一个空值,查询count(*)和count(name)观察区别:
select count(*), count(name) from test;
二、count()的应用技巧
由于count()是一个聚合函数,因此它在统计时会扫描符合条件的所有记录,如果我们需要统计多项汇总数据,常规的SQL会一次次的扫描结果集,每次统计出一个结果,而利用一些技巧,我们可以一次扫描统计出多个汇总数据。
2.1 同时统计多列
首先改造一下测试数据,假设这是一张销售明细表,新增产品和价格列:
alter table test add product varchar(32), add price decimal(10,2);
truncate table test;
insert into test values(null,‘Vincent’, ‘Table’, 100),(null,‘Vincent’, ‘Chair’, 50),(null,‘Vincent’, ‘Chair’, 50),(null,‘Victor’, ‘Table’, 100),(null,‘Victor’, ‘Chair’, 50),(null,‘Victor’, ‘Chair’, 50),(null,‘Victor’, ‘Chair’, 50);
select * from test;
假设现在我有下列问题:
- Vincent卖了几件商品?
- Victor卖了几件商品?
- 产品椅子总销量是多少(不分人员)?
- 所有产品的销售总金额是多少?
由于这几个问题的分组条件都不同,无法用1个group by条件概括。按照常规思路,第1,2个问题应该是count(*)然后group by name,第三个问题应该是count(*) where product=‘Table’,最后在全表扫描一次求出sum(price),即总金额:
select name,count(*) from test group by name;
select count(*) from test where product='Chair';
select sum(price) from test;
虽然上面得到了4个问题的答案,但对表查询了3次,假设在生产环境这个表非常大,那么性能必然低下。稍微优化一下,我们可以用一次查询同时回答上面4个问题:
select
count(name='Vincent' or null) Vincent的销量,
count(name='Victor' or null) Victor的销量,
count(product='Chair' or null) 椅子的总销量,
sum(price) 总销售金额
from test;
这里利用了count(column)不会统计null的特性,将条件转移到count()函数的内部,实现了一次扫描,多个维度统计。
2.2 利用执行计划
当表中的数据特别大,统计时间特别长,而我们需要的结果又不需要很精确时。可以通过执行计划来查看预估的数量,利用这种方式可以在不实际执行查询的结果下快速得到结果:
示例:统计表中某类数据的数量,直接通过执行计划查看,而不实际执行SQL:
explain select count(*) from test;
注意这种方法之适合不需要精确数字的场景,执行计划中的rows是根据统计信息估计出来的,而统计信息本来就是个采样值而且可能已经比较过时了,使用这个方法前可以先执行 analyze table tab_name; 更新一下统计信息。