vlambda博客
学习文章列表

面试总结 (一)mysql中的select count

面试首先要了解面试官会问什么?


如这个问题,面试官问select count,我认为想问的是:


1、select count的有什么用?

count() 的语义。count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL,累计值就加 1,否则不加,最后返回累计值


2、select count怎么用?

count(*)、count(1)、count(主键id)、count(字段/列)的区别?

count(*)、count(主键 id) 和 count(1) 都表示返回满足条件的结果集的总行数;而 count(字段),则表示返回满足条件的数据行里面,参数“字段”不为 NULL 的总个数。


3、select count的运作?

myisam引擎中,myisam会将表的总行数存起来,执行select count时直接读出总行数返回;(当select count后带有where语句时依然需要遍历全表

innodb引擎中,需要遍历全表去计算得到总行数。并涉及到MVCC的内容。



怎么答?

select count是mysql统计表总行数的语句(扫描表的总行数),在旧版本默认引擎是myisam的mysql中,myisam会将表的总行数存起来,执行select count时直接读出总行数返回,在新版本默认引擎是innodb的mysql中,需要遍历全表去计算得到总行数。



扩展提问一:为什么innodb引擎不像myisam引擎那样把行数保存起来?


这是因为innodb支持事务特性,在innodb引擎里面,MVCC会给每行数据都保存一个版本号,每当新的事务启动,版本号就会自动递增。(背景描述)

在不同的事务里所能看到的行数是不一样的,这是因为在innodb遍历全表时,查找到的每一行数据都需要检查数据的版本号对自身事务是否可见,如果可见则统计计数加一,如果不可见,则忽略。同时也会存在一个事务删除了某一行数据但并未提交,其他事务依然可以认为这一行数据存在。(说明原因)


扩展提问二:count(*)、count(1)、count(主键id)、count(字段/列)的区别?


直接说答案再说原因,这样面试官听到你答案正确就觉得你应该会,并会积极听下去

按照效率排序的话,count(*)=count(1)>count(主键id)>count(字段/列)


原因是:相比于count(*)和count(1),count(主键id)会在遍历每一行的时候把id给取出来,发现id是不可能空的才统计计数加一,而count(字段/列)则会把对应的字段读出来,并判断该字段是否可能有空,如果可能有空,还需要判断是否为空。


知识点:


mysql使用select count(*)在遍历全表进行统计时,会优先选择基数最小的普通二级索引树,而不是在主键索引树中遍历查找。




参考资料:

《mysql实战45讲》林晓斌