数据库-操作及原理|count(*)count(1)和 count(col)区别


数据库啊~

    • 1. 背景
    • 2. 知识点
    • 3. 补充实验
    • 4. 结论

1. 背景 初识SQL,在实习,跑数据中,写了点SQL来检查数据:数据库-操作及原理|count(*)count(1)和 count(col)区别
文章图片

select count(*) from Jzt_jdKuaiche_accountStatement_promotionUnitStatement where startTime='2019-06-01' and platform='all' select count(*) from Jzt_jdKuaiche_accountStatement_promotionUnitStatement where startTime='2019-06-01' and platform='PC' select count(*) from Jzt_jdKuaiche_accountStatement_promotionUnitStatement where startTime='2019-06-01' and platform='mobile'`

有点麻烦,参照教程里的例子group by了下~
select platform,startTime,count(1) from Jzt_jdKuaiche_accountStatement_promotionUnitStatement where dateType='month' and startTime='2019-06-01' GROUP BY platform,startTime order by startTime

对于一个初学者
是在有点困惑:count(*),count(1),count(col)有什么区别?
select platform,startTime,count(*) from Jzt_jdKuaiche_accountStatement_promotionUnitStatement where dateType='month' and startTime='2019-06-01' GROUP BY platform,startTime order by startTime

我把上面语句里的count(1)改成count(*),执行下来然后并没有发现什么区别~
2. 知识点 先来学习下count():
1、COUNT(*) 函数返回表中的记录数:
语法:
SELECT COUNT(*) FROM table_name

2、COUNT(column_name) 函数返回指定列的值的数目(NULL 不计入):
语法:
SELECT COUNT( column_name) FROM table_name

3、COUNT(DISTINCT column_name) 函数返回指定列的不同值的数目:
语法:
SELECT COUNT(DISTINCT column_name) FROM table_name

问了问同事,我得到的回答是:在SQL里 * 号代表所有,查询数据量的数量级达到千以上就执行效率就会比count(1)要低。在查询小批量数据,count(*)和count(1)没啥区别。
但是:
count(*)和count(1)具体怎么执行的呢?
count(1)里面1究竟指代什么?
留待慢慢深入~
3. 补充实验 断断续续学习mysql也有一阵了,补充一下对count的理解~
orders表结构如下(测试环境mysql5.7.30,Innodb存储引擎):
数据库-操作及原理|count(*)count(1)和 count(col)区别
文章图片

orders表只有PK约束,各字段未建索引
造点数据:
import randomfor i in range(1, 10001): # "insert into orders(o_id, s_id, f_name, f_price) values(1, 101, 'apple', 5.2)"%() # "insert into orders(o_id, s_id, f_name, f_price) values({},{},{},{}".format(o_id,s_id,f_name,f_price); # [o_id, s_id, f_name, f_price] suppliers = [101, 102, 103, 104, 105] fruits = ['apple', 'pear', 'pineapple', 'banana', 'blueberry', 'strawberry', 'orange', 'melon', 'blackberry']o_id = i s_id = random.choice(suppliers) f_name ="\'"+ random.choice(fruits)+"\'" f_price = str(random.uniform(1, 20))[:5]sql = "insert into orders(o_id, s_id, f_name, f_price) values({},{},{},{}); \n".format(o_id, s_id, f_name, f_price); print(sql) with open("D:/Users/***/Desktop/order.txt", "a") as f_new: f_new.write(sql)

一万条数据有点少,count下来时间都很短~
执行计划:
数据库-操作及原理|count(*)count(1)和 count(col)区别
文章图片

可以看出,该场景中count(*) 和count(1)还有count(pk_index_col)等价,都统计行记录,并且都走PK索引。
加个索引试试~
数据库-操作及原理|count(*)count(1)和 count(col)区别
文章图片

就走索引了~
but~
数据库-操作及原理|count(*)count(1)和 count(col)区别
文章图片

count(*),count(1)都不走主键索引啦!
原因嘛,细想也很简单:
主键索引也就是聚集索引,聚集索引的BTREE的叶子结点存储的是完整的行记录,而我们新建的name_index也就普通索引,它存储的是带有主键值的行记录,占据空间小,innoDB为了合理使用资源,选择占用空间最小的索引进行统计。
count(*),count(1)有区别吗?
5.7官方文档有句话如下:
数据库-操作及原理|count(*)count(1)和 count(col)区别
文章图片

in the same way! count(*),count(1)就是没区别一毛一样了~
4. 结论 所以,我们大概可以得到以下几点:
(1)count(col)和count(*)统计的维度是不一样的:
? count(*)统计表中的记录数;
? count( col )统计表中col列的不为空的记录数;
(2)count( * ) = count(1)≈ count(index_col)具体场景具体讨论;
(3)有索引时,count( * ),count(1)优先选择占用空间最小的索引进行统计;
(4)count(col) 其中col列有索引即走索引,无索引,就全表扫描。
待补充实验:
  1. 行记录存在空值情况
  2. 条件查询统计情况
【数据库-操作及原理|count(*)count(1)和 count(col)区别】参考文献:
[1]SQL COUNT() 函数 https://www.w3school.com.cn/sql/sql_func_count.asp
[2]Select count(*)和Count(1)的区别和执行方式 - CareySon - 博客园 https://www.cnblogs.com/CareySon/p/DifferenceBetweenCountStarAndCount1.html
[3]https://zhuanlan.zhihu.com/p/28397595

    推荐阅读