标签:优化 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来说,也可以用这样的方法进行优化,因为字段已经排序,可以直接在获得的记录中进行分组计算。
三.
几个原则:
标签:优化 regex loop sts 建立 ext 查看 tail 速度
原文地址:http://www.cnblogs.com/CLFR/p/6409161.html