MySQL优化--关联查询、子查询、排序分组的优化

一、关联查询的优化

在做join的时候,原理为驱动表(主表)做全表扫描,对子表(被驱动表)可以利用索引进行优化,而驱动表的全表扫描是必须存在的。

建表sql

 
CREATE TABLE IF NOT EXISTS `class` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`id`)
);
CREATE TABLE IF NOT EXISTS `book` (
`bookid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`card` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`bookid`)
);

当有一条查询SQL为:

SELECT * FROM class LEFT JOIN book ON class.card = book.card;

explain一下,发现两张表都是ALL全表扫描。我们尝试进行增加索引来进行优化。因为驱动表必须是进行全表扫描,所以我们对被驱动表的连接条件进行建立索引,发现被驱动表的查询type变为了ref,且rows也明显优化。

总结:1.保证被驱动表的join字段已经被索引

2.left join  或 right join时,将小表作为驱动表(因为要必须要进行全表扫描),将数据量大的表作为被驱动表。

3.inner join时,MySQL会自动把小结果集的表作为驱动表,这不需要我们关心,但高版本MySQL(5.8)后,inner join的优化策略改变了,改变为当大表作为驱动表时,对大表建立 auto_key 索引。这不需要过多关注。

4.子查询尽量不要放在被驱动表,因为查询出的衍生表无法建立索引。

5.能用连接查询,就不要用子查询。

二、子查询优化

根据业务需求,当在子查询中出现 not in 字段时,完全可以用连接查询代替

A.id not in (select B.id)

可以替换为

A left join B on A.id = B.id where B.id = null

三、排序和分组优化

众所周知,在order by 和group by 子句中用到的字段加索引会大大提高查询效率,并可以有效避免 file sorted这种严重影响效率的情况。

首先建立一个索引

 create index idx_age_deptid_name on emp (age,deptid,name)

在Order by 子句的优化:

1.无过滤,不索引

#无法用到索引
explain  select SQL_NO_CACHE * from emp order by age,deptid; 
 #使用到了索引
explain  select SQL_NO_CACHE * from emp order by age,deptid limit 10; 

在Oder by子句中,如果想用到索引,必须要有限制条件,如where 或limit ,不然无法用到索引

2.顺序错,必排序(file sorted)

3、  explain  select * from emp where age=45 order by deptid;
 
 
4、explain  select * from emp where age=45 order by   deptid,name; 
 
5、explain  select * from emp where age=45 order by  deptid,empno;
 
6、explain  select * from emp where age=45 order by  name,deptid;
 
7、 explain select * from emp where deptid=45 order by age;

MySQL的 Optimizer会自动优化where中的查询顺序,但不会对order by子句中的字段顺序进行优化,所以只有当oder by 后的字段顺序与索引字段顺序一致时 才可以用到索引

3.方向反,必排序

#可以用到索引
explain select * from emp where age=45 order by  deptid desc, name desc ;
#没有用到索引
explain select * from emp where age=45 order by  deptid asc, name desc ;

order by 后的字段排序必须一致,如不同,则索引失效。

4.我们都知道sql的执行顺序为先执行where 再执行 order by 或 group by,如果where中有范围查询怎么办?范围查询的字段右边的索引全部失效,这时就要综合考虑。

结论: 当范围条件和group by 或者 order by  的字段出现二选一时 ,优先观察条件字段的过滤数量,如果过滤的数据足够多,而需要排序的数据并不多时,优先把索引放在范围字段上。反之,亦然。

group by 子句的优化与order by基本一致,唯一的区别就是group by 使用时,即使没有过滤条件,也可以直接使用索引。

四、覆盖索引

简单说就是,select 到 from 之间查询的列 <=使用的索引列+主键,这就是为什么在查询中不建议使用 * 的主要原因。

覆盖索引不会进行大级别的优化,但在没有办法的时候,还是可以试一试,

<>无法用到索引,但可以通过覆盖索引去利用上索引。

发布了227 篇原创文章 · 获赞 77 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/m2606707610/article/details/103698942