单表查询sql笔记
单表查询sql的执行,大体上可以分为两步。“二级索引find”和“回表select”。
“二级索引find”。
有两层含义,一方面是利用二级索引去找,另一方面是利用索引进行过滤(即索引条件下推)。
因此正确利用索引也有两层含义,一是利用的索引长度越多越好,二是经过索引find之后,能过滤掉的数据越多越好。
“回表select”。
因为二级索引毕竟包含的字段列有限,如果我们select的字段不能被索引全包含,在“二级索引find”结束后,根据得到的主键id,需要去一级索引上查询所需的列。这个过程叫做回表。而“二级索引find”阶段得到的主键id并非有序的,意味着回表是一个随机IO的过程,也就注定了回表是一个成本较高的操作。这也就是为什么有时候mysql宁愿全表扫描也不愿走索引的原因。
索引条件下推的出现就是为了节省回表的成本。
当然,如果我们最终select出来的字段能够被二级索引完全包含,“二级索引find”阶段之后,就不需要进行回表操作,这就是索引覆盖。当出现索引覆盖时,执行计划中Extra列将会通过Using index告诉我们。
回到我们的sql中,表中明明存在与查询条件极度匹配的联合索引(period_year、period_month、user_je_source_name、status),但是mysql却不用,这说明了什么?
说明了period_year、period_month、user_je_source_name、status这些条件并不具备很高的区分度,真正具有区分度的其实是在employee_number、can_auto_push和is_delete当中!
通过控制变量法,对employee_number、can_auto_push和is_delete取不同值时的数据量对比,发现当is_delete分别取0和1时,数据量差别极大。
可以看到,对于is_delete字段,取值1时,数据量在50w+,取值0时,数据量在1000+。
而我们所要查询的正是is_delete=0的数据。
结合我们第二阶段对执行计划的解读。最终可以确定此sql执行时间过长的瓶颈点就在回表。
该sql只想查询is_delete=0对应的1000+条数据,获取这些数据可能几次回表就能得到。但是通过“索引find”阶段,我们并不能对is_delete字段进行过滤,导致“索引find”阶段会得到50w+的id,然后对这50w+的id进行回表。回表后通过Using where对is_delete字段进行过滤。
整个过程慢就慢在回表。
- 点赞
- 收藏
- 关注作者
评论(0)