sql优化(二)

传送门 sql优化(一)http://my.oschina.net/zimingforever/blog/59515

今天突然发现昨天写的一个sql效率的博文上了OSC首页推荐。感谢国家。

明天又要开周会分享sql优化了。话说上次介绍这次要讲的是mysql的分页优化

4 分页优化【优化※※※】

mysql的分页比oracle简单多了,用limit start,offset就可以实现。

先来一种简单的情形

SELECT * FROM `employees` LIMIT 200000,1000;

查出20W起的1000条数据,时间为0.119s

SELECT * FROM `employees` where emp_no>= (select emp_no from employees LIMIT 200000,1) LIMIT 1000;

这种优化的思路是找出empno大于第20W的是emp_no起的1000条数据,时间为0.065s. 但是这种优化方法的缺点是这个字段必须要连续的,并且要是有where的话可能就获得不到了正确的数据了。

其实mysql的分页的思路是这样的,先全表扫描找到符合条件的语句,然后一行一行去掉startno之前的数据,在取出offset后数据,最后返回这些结果。速度慢在了去掉startno的数据,所以这也是为什么越大的分页执行的越慢。这倒是给我们一个优化的思路,我们去之前无用的数据能否优化。

SELECT * from employees where gender ='M' limit 100000,1000;

通过explain查看执行计划发现走了全表扫描。执行时间为0.107s

给gender加索引发现执行时间并没有优化(而且还多了。%>_<%)

直接给出优化方法

SELECT * from employees e1,(SELECT emp_no from employees where gender ='M' limit 100000,1000) e2 where e1.emp_no=e2.emp_no

上数据,执行时间为0.069s, 看来优化了不少

查看下执行计划

1 PRIMARY <derived2> ALL                                         1000

1 PRIMARY e1                 eq_ref PRIMARY PRIMARY 4 e2.emp_no 1

2 DERIVED employees         ALL                                         299698 Using where


看来执行的顺序是 先从emoployee中查出gen符合条件的数据,然后根据E2的主键找出第10000及之后的1000条数据。
然后再和E1做join,在从derived中取出1000条全表。速度快在了之前是所有的字段都算上去排除10000条数据,优化后是根据主键来排除前10000条数据。

补充一下,这个说法有些含糊。引用网上的一个说法比较清楚
从原理上说,MySQL是根据二级索引来获取符合条件(b=1)的记录主键(id),再根据记录的主键(id)去查询相应的记录。一种是,先查询出2010条记录的id,回表查询数据,再将2010条完整记录发给MySQL以便筛选最后10条; 另外一种是,先查询出2010条记录的id,筛选出最后10条记录的id再回表查询,最后返回10条完整记录给MySQL。 在回表次数很多(limit决定)的情况下,显然第二种方法是比较快的,而MySQL默认采用了第一种。

下面这种写法很易读啊,先选择出符合条件的数据的emp_no(主键),然后再找出employees表中emp_no在结果集中的数据。但是遗憾的是mysql语法报错了.....下面是不正确的写法哈。
select * from employees where employees.emp_no in (SELECT emp_no from employees e where e.gender ='M' limit 100000,1000);


总结一下,mysql的limit的优化对于大数据量的分表还是很有帮助的,优化的思路就是减少回表的数据,减少回表的IO,写法就是 select t.* from tab t , (select id from tab limit m,n) tmp where tmp.id =t.id


 

你可能感兴趣的:(sql优化(二))