码迷,mamicode.com
首页 > 数据库 > 详细

Mysql语句优化

时间:2017-02-17 11:55:33      阅读:227      评论:0      收藏:0      [点我收藏+]

标签:优化   regex   loop   sts   建立   ext   查看   tail   速度   

mysql中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询。exists与in性能的好坏不能一概而论,要根据表的大小,索引来决定。

一.

如果查询的两个表大小相当,那么用in和exists差别不大。 

如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in: 

例如:表A(小表),表B(大表)

1:

select * from A where cc in (select cc from B) 效率低,用到了A表上cc列的索引。

上面的查询首先会从B中查出所有的cc,因为B表是大表,所以会select cc from B会产生许多的cc(而且会全表扫描B表),然后这些cc值按照顺序一个一个从A表取出相应的记录,所以只会用到A表的索引,主要的开销在全表扫描B上。

select * from A where exists(select cc from B where cc=A.cc) 效率高,用到了B表上cc列的索引。 

上面的查询首先会全表扫描A,得到A的所有记录,然后用每条记录中的cc值作为查询条件在B表中查询,由于有索引,所以查询很快,避免的大表的全表扫描,只扫描了小表A,因此效率比较高。

2:

select * from B where cc in (select cc from A) 效率高,用到了B表上cc列的索引;

同样,上述查询只全表扫描了A,大表查询用的是索引。

select * from B where exists(select cc from A where cc=B.cc) 效率低,用到了A表上cc列的索引。 

当A和B表在cc列上都没有索引时,in和exists都需要全表扫描A表和B表,查询速度差别不大。

 not in 和not exists如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快

 

二.优化group by和order by

分组和排序算是mysql中比较消耗cpu的操作,当我们用explain工具来查看sql时,往往会看到Extra那一栏都会出现using temporary,using filesort(临时表和文件排序),因为得到的数据并非是已经分组的和排序的,需要额外的空间来进行分组排序,我们可以通过建立合适的索引来优化,因为索引是已经排序的。举例说明:

假设有表A,有如下几条数据:字段是a(主键),b,c,d。

a                 b                   c                         d

1                 1                   2                         3

2                 2                   3                         1

3                 1                   2                         2

4                 1                   2                         5

5                 1                   2                         4

我们执行select * from A where b<2 order by d desc

因为b字段没有索引,所以需要全表扫描A,那么扫描过后得到数据

1                 1                   2                         3

3                 1                   2                         2

4                 1                   2                         5

5                 1                   2                         4

此时d字段是乱序的,那么mysql需要临时开辟一段内存空间(临时表)来保存扫描后的结果,然后对d字段进行排序(文件排序)。

如果我们在d字段加上索引,那么可以按照索引的顺序来扫描全表,扫描后的结果就是排序的结果。

d字段的索引是这样的:

5  4

4  5

3  1

2  3

1      2

上面每一行的前一个数是d字段的值,后一个字段为d字段所在行的主键a的值。按照d字段索引的顺序扫描全表,首先扫描a=4的行,发现这一行的b<2,满足条件,则保留

4                 1                   2                         5

接下来扫描a=5的行,发现这一行的b<2,满足条件,则保留

4                 1                   2                         5

5                 1                   2                         4

。。。。。。。。。

接下来扫描a=2的行,发现这一行的b=2,不满足,则舍弃

4                 1                   2                         5

5                 1                   2                         4

1                 1                   2                         3

3                 1                   2                         2

扫描过后的记录就是符合条件的记录,不需要临时表和排序。对于gropup来说,也可以用这样的方法进行优化,因为字段已经排序,可以直接在获得的记录中进行分组计算。

三.

几个原则:

  1. 小表(记录在几万以内)查询,无论有无索引,查询性能相差不大。
  2. 和大表做join,关联字段上一定要加索引
  3. join操作一般用小表驱动大表
  4. 尽量不要使用like,regex,or
  5. 尽量不要在查询的列上做计算,如where length(detail)>15 detail字段的长度大于15,这种条件都会进行全表扫描,即使detail有索引。
  6. 尽量不给大字段做索引,比如 detail varchar(256),这种索引耗费cpu,耗费空间,而且查询效率低。如果业务允许的话,可以建个前缀索引。

Mysql语句优化

标签:优化   regex   loop   sts   建立   ext   查看   tail   速度   

原文地址:http://www.cnblogs.com/CLFR/p/6409161.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!