一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情
上篇讲到MySQL索引失效的场景,我们应该尽量避免因为SQL的书写导致索引的失效问题,下面本篇文章将针对SQL查询优化描述如何优化SQL,如何合理的创建索引。
查看表索引:
先将表class,student的全部索引删除:
class表有10w数据,student表有500w数据如下图:
数据库版本5.7,存在缓存,先将其关闭:
重启,在看缓存
如果不想关闭全局缓存可以不加global,或者在查询select关键字后加上
sql_no_cache。
1.左连接查询
如下SQL:explain select * from class c left join student s on s.classId = c.id;
可以看到当前两条记录都没有使用到索引,在被驱动表(对于left join来说就是右边的),
alter table student add index idx_classId(classId);,查看索引:
在执行上面的SQL,如下图:
在这里可以看出扫描行数相差将近100倍,由于数据量较大,查询直接卡死,时间差异对比使用如下SQL:
select * from class c left join student s on s.classId = c.id where s.classId = 1;
在限制条件的情况下都相差了十多倍,真实情况数据条件不可能就一条。
小总结:所以对于left join来说左边反正是必须要有的,所以对于被驱动表,也就是大表需要建立索引,降低扫描的时间,(ps:right join其实和left join是一样的,你可以将其反过来理解这里不过多赘述)。
2.内连接
先删除索引:
我们都知道小表驱动大表,这次我们故意将数据量多的student表放到前面,看MySQL如何选择,
explain select * from student s inner join class c on c.id = s.classId where s.classId = 1;
在讲MySQL性能分析的
explain的时候,我们详细的说过,id相同的由上往下执行,所以MySQL选择将class表
为驱动表,先执行的为驱动表。
下面是执行时间的差别:
我们看下执行计划发现扫描行数少了很多:
补充:当join连接的字段两边数据类型不一致时导致的索引失效。
修改表student的字段classId的类型为字符varchar(50),
alter table student modify classId varchar(50);
执行:explain select * from class c left join student s on s.classId = c.id where s.classId = 1;
查看执行计划我们可以发现明明在student的classId字段上建立了索引但还是全表扫描,如下图:
总结:
- 使用left join要将小表放到前边,减少循环的次数。
- 使用inner join的时候MySQL会自动将小表作为驱动表。
- 使用join的查询连接字段必须要建立索引。
- 使用join的查询连接的字段数据类型必须一致。