美文网首页
mysql查询优化

mysql查询优化

作者: 水木清华_f221 | 来源:发表于2018-09-08 19:04 被阅读13次

SQL优化,是一个非常重要技能;而我们常说的SQL优化,一般指的是查询优化。

准备工作

首先,我们需要创建一张表a

CREATE TABLE `a` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `key_A1` int(11) DEFAULT NULL,
  `name` varchar(50) DEFAULT NULL,
  `key_A2` int(11) DEFAULT NULL,
  `key_A3` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `idx_a_id` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=13244 DEFAULT CHARSET=utf8;

插入了10万条数据

mysql> select count(*) from a;
+----------+
| count(*) |
+----------+
|   100000 |
+----------+

然后建个复合索引

alter table a add index idx_a_key123(key_A1, key_A2, key_A3)

其次,你需要对explain关键字有一定的了解(可以查看我另一篇文章explain详解)以及profile的相关知识(profile的使用

order by

order by优化,其实就是索引优化,具体看下索引使用技巧;

order by 也是遵循左前缀法则的,不同的是,它需要带上where后面的条件,也就说,如果where条件加上order by的顺序如果是索引的顺序,那么order by就可能根据索引来进行排序。

文字说的可能不好理解。下面来看案例:

图片.png

这样就能利用索引去排序,不会产生内排序

没用上索引则会导致filesort,内排序也会影响性能,最好优化;


图片.png

上面都是左前缀法则。

有点需要注意的是:order by如果有多个字段进行排序,则字段顺序要和索引中的字段顺序一致,索引排序的规则规则也要一样(要么都是升序,要么都是降序)

当然如果数据量大,你可能需要调整sort_buffer_size和max_length_for_sort_data参数的设置。

group by

group by优化和order by类似,group by的实现也是先排序,然后再分组;只不过group by多了个having,能再where中过滤的就在where中过滤,where过滤要比having高。如果group by没用上索引,会有临时表产生,临时表会严重影响性能。

图片.png 图片.png

上面两个例子中只是group by字段的顺序不一样,但是性能确实天差地别。

小表驱动大表

多表查询,有个关键的因素,就是小表驱动大表,先加载小表会会减少磁盘IO;这里不得不提in和exists

曾经看到不少优化建议,建议使用exists,不建议使用in,这个其实是不对的。

in

in的执行过程是,先执行子查询,然后执行主查询,如果子查询中的表相对于主表非常小的话,查询是比较快的。

exists

exists的执行流程是,从主查询中取数据然后去子查询中判断是否为true,true则保留,false则不保留;这个实际上先执行的主查询,如果主查询的表非常大,这回非常影响性能。

案例

图片.png
这里我添加了一张表b,只添加了10条记录
select * from a where key_A1 in (select key_B1 from b)
select * from a where EXISTS (select 1 from b where b.key_B1 = a.key_A1)

上面这两条SQL表达的意思是一样的,但是性能大概了差了20倍,使用in要比exists快20倍。

使用in的explain分析如下:

图片.png

使用exists:


图片.png

使用in现加载的是子查询,使用exists先加载的是exists外面的查询;
而a表是大表,b是小表;我们应该选择先加载小表,故应该用in查询。至于为什么要先加载小表,可以这样来记,这相当于一个嵌套的循环,外层循环需要和磁盘进行IO,外层循环的次数越少,性能就越高。

通过profile查看exists:

图片.png

发现存在大量的数据传输。

distinct

distinct和order by同时使用;一定小心,这很可能会导致索引的失效。

图片.png

使用distinct一定要注意,distinct出重实际上也是通过排序的。所以尽量让distinct的那个字段能够使用索引。where(不能有范围)后面的字段(按顺序)加上distinct的字段如果刚好和索引的顺序一致就能够使用上索引了,实际上也是左前缀法则;加上order by和group by 就无法使用索引了,相当于中间断了。

相关文章

网友评论

      本文标题:mysql查询优化

      本文链接:https://www.haomeiwen.com/subject/fwukgftx.html