MySQL之查询优化

149 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

上篇讲到MySQL索引失效的场景,我们应该尽量避免因为SQL的书写导致索引的失效问题,下面本篇文章将针对SQL查询优化描述如何优化SQL,如何合理的创建索引。

查看表索引:

image.png

先将表class,student的全部索引删除:

image.png

class表有10w数据,student表有500w数据如下图:

image.png

数据库版本5.7,存在缓存,先将其关闭:

image.png 重启,在看缓存

image.png 如果不想关闭全局缓存可以不加global,或者在查询select关键字后加上sql_no_cache

1.左连接查询

如下SQL:explain select * from class c left join student s on s.classId = c.id;

image.png 可以看到当前两条记录都没有使用到索引,在被驱动表(对于left join来说就是右边的), alter table student add index idx_classId(classId);,查看索引:

image.png

在执行上面的SQL,如下图:

image.png 在这里可以看出扫描行数相差将近100倍,由于数据量较大,查询直接卡死,时间差异对比使用如下SQL:

select * from class c left join student s on s.classId = c.id where s.classId = 1;

image.png

在限制条件的情况下都相差了十多倍,真实情况数据条件不可能就一条。

小总结:所以对于left join来说左边反正是必须要有的,所以对于被驱动表,也就是大表需要建立索引,降低扫描的时间,(ps:right join其实和left join是一样的,你可以将其反过来理解这里不过多赘述)。

2.内连接

先删除索引:

image.png

我们都知道小表驱动大表,这次我们故意将数据量多的student表放到前面,看MySQL如何选择,

explain select * from student s inner join class c on c.id = s.classId where s.classId = 1;

image.png 在讲MySQL性能分析的explain的时候,我们详细的说过,id相同的由上往下执行,所以MySQL选择将class表 为驱动表,先执行的为驱动表。

下面是执行时间的差别:

image.png

我们看下执行计划发现扫描行数少了很多:

image.png

补充:当join连接的字段两边数据类型不一致时导致的索引失效

修改表student的字段classId的类型为字符varchar(50),

alter table student modify classId varchar(50);

image.png

执行:explain select * from class c left join student s on s.classId = c.id where s.classId = 1;

查看执行计划我们可以发现明明在studentclassId字段上建立了索引但还是全表扫描,如下图:

image.png

总结

  1. 使用left join要将小表放到前边,减少循环的次数。
  2. 使用inner join的时候MySQL会自动将小表作为驱动表。
  3. 使用join的查询连接字段必须要建立索引。
  4. 使用join的查询连接的字段数据类型必须一致。