上午刚面一个Java开发岗,深刻体会到自己基础的不扎实,写下此篇,谨记在心。
面试官:你平时如何统计一张表的记录数量
菜鸡小川:count(1)
面试官:那你认为count(1),count(索引字段),count(*)之间谁的效率高
菜鸡小川:count(1)==count(索引字段)>count(*)--非常干脆的回答了
回答完,楞了一下,死去的记忆似乎想唤醒我,but,没给我唤醒
不知有多少同学和我一样,认为count(*)肯定是最慢的。以为和select * 一样肯定是要扫所有数据怎么都得慢点。
只能说八股不是靠背的,还得深刻理解啊。(但我每次看完理解了又忘了。。。注定天资平平,理解的不够深刻)
不过,好记心不如烂笔头,那就写下来分析一下吧。
首先分析count()
count()是一个聚合函数,作用就是统计记录数据的数量。准确的说是统计参数不为null的行记录数量。
举个例子,count(id)就是统计id不为空有多少行数据。
特殊:count(1)就相当于全表统计了,因为1永远不为null嘛。
count()是如何做到统计数量的呢
这就的说到mysql的存储引擎和服务层了。mysql的存储引擎是用于存储具体的记录的,服务层是用于做一些基础的计算。
那我们先分析一下count(主键索引),底层是如何做到的:
首先假设没有二级索引了,当发起这个命令时会去找这个主键索引的b+树并找到第一个节点依次向后扫描,每每扫到数据就返回server层做判断,判断这个字段是否为空,如果不为空则数量加1,直至扫到最后一个节点的最后一条记录,然后再将计算好的数量返回给客户端。
所以,当你直接使用count(1)的时候,就省去了判断null的只一个步骤,所以自然是更快的。
那count(*)呢,其实呀,一样的,count(*)相当于count(0),所以也是不需要判断的。这可不是我乱说的,mysql官方专门提出了:
那有人会好奇,前面说的是假设没有二级索引,那如果有呢。
如果有二级索引,就会直接走二级索引,这个也比较好理解,因为,二级索引这棵树的叶子节点只需要存主键,所以自然能存的内容更多,那树也会比较窄,io的效率肯定是要高一些的。
总结一下:count(1)==count(*)>count(索引字段)