一 , 关联查询优化

Join语句的三种执行方式:SNLJ,INLJ,BNLJ

我们用这条sql举例,假设t1中有n条记录,t2中有m条记录

MySQL 查询中间表优化 mysql join查询优化_MySQL 查询中间表优化

SNLJ(Simple - Nest - Loop - Join)

最朴素的Join查询方式,执行流程就是:从t1中取出一条数据,拿这条数据的a字段与t2中比较,找到目标行返回,重复此操作。 这样的时间复杂度是最高的,O(N * M)。

INLJ(Index - Nest - Loop - Join)

先看图

MySQL 查询中间表优化 mysql join查询优化_数据_02

可以看到,我们加入了索引,也就是优化了拿t1的数据去匹配t2的操作,在SNLJ中我们需要一条一条的匹配,但是加入了索引之后,这个查询操作的时间复杂度就大大降低了,O(n * logm)。但是增加了一个回表操作

 BNLJ - (Block - Nest - Loop - Join)

MySQL 查询中间表优化 mysql join查询优化_数据库_03

在SNLJ中我们是一条一条数据从t1拿出来,现在是一整块数据拿出来,那么自然匹配速度就快了,但是要更多的内存空间

二,子查询优化

        子查询可以帮助用更短的sql解决更复杂的问题,但是它的执行效率不高,原因主要有三个:

1.执行子查询时,mysql需要为内层查询的查询结果建立一个临时表,然后外层查询再从临时表中找到自己需要的记录。查询完毕后要撤销临时表。这对系统资源来说无疑是压力山大。

2.子查询中产生的临时表没有索引,索引查询起来性能很差

3.对于数据量很大的子查询,效率会更低

我们可以通过Join来连接查询以此替代子查询

 

三,排序优化

我们已经对where条件字段创建了索引,为什么还要对Order by也创建索引呢?

1.在数据量大的情况下我们要尽量避免系统排序(file sort),节省系统资源

2.在无法使用索引的情况下,我们需要对file sort进行优化

filesort的两种排序方式:

单路排序:把需要排序的字段和查询的字段全部拿出来放在sort buffer中进行排序(前提是sort buffer够大)

双路排序:仅将需要排序的字段和可以反映行具体位置的字段取出到sort buffer进行排序,再根据排序的结果回到原表中取数据,这个过程要经历两次的IO操作

所以总体来说单路排序效率要高于双路排序,但是对sort buffer的大小有要求,我们需要尽可能保证其容量足以满足单路排序

四,索引覆盖

什么是索引覆盖?

简单理解就是索引包含了我们查询的所有字段。比如你创建了一个index(a,b,c),而你要查询的字段是a,b,那么此时通过该索引找到的数据就是你所需要的数据,不需要再进行回表操作

索引覆盖的优点:

1.减少了磁盘IO次数

2.将随机IO变为顺序IO

缺点:

索引的维护是需要成本的

五:索引下推(Index Condition Push down)简称ICP

MySQL 查询中间表优化 mysql join查询优化_字段_04

MySQL 查询中间表优化 mysql join查询优化_字段_05

在该sql语句的场景下,假如没有索引下推,那么我们会先根据索引找到符合zipcode找到符合条件的所有行,并且一行一行的回表,去主键索引判断是否符合后面的like条件。  但是有索引下推回怎么样呢? 它会在根据索引找到所有符合条件的数据后,根据后面的like条件(只能是lastname,因为我们的索引没有包含address)进行一次筛选,留下满足后两个条件的数据,再用这些数据回表。可能一开始有1000条数据,筛选过后就只有100条了,极大地减小了回表的压力和随机IO的次数。

所以索引下推,也可以称为索引条件下推,就相当于是在二级索引和主键索引之间的一道过滤墙,把一些不满足条件的数据先过滤掉,减轻了回表的压力。

六:关于select *select (具体字段)

        建议要查哪些字段就写哪些字段。

        首先,我们有可能不清楚表中到底有多少个字段,万一表非常大,你要查的数据又很少,那就得不偿失了。

        其次,mysql会对*进行解析,解析成对应字段名称,这是比较耗时的操作

        最后,select * 无法使用索引覆盖