好久没有准备sql优化的内容了。
5 子查询优化【优化※※※※】
子查询因为它的高可读和使用习惯,是我们的程序中常用的一种写法,但是其实它的效率并不高
举例子说明,查询在部门d005的员工信息
SELECT * from employees where emp_no in (SELECT emp_no FROM `dept_emp` where dept_no='d005')
执行时间1.4s,执行结果85707条。
查看执行计划
explain extended SELECT * from employees where emp_no in (SELECT emp_no FROM `dept_emp` where dept_no='d005');
1 PRIMARY employees ALL 300473 100 Using where2 DEPENDENT SUBQUERY dept_emp unique_subquery PRIMARY,emp_no,dept_no PRIMARY 16 func,const 1 100 Using index; Using where
居然还走了依赖子查询,效率更低啊。
换成多表查询吧(多表查询和join on, join using的效率是一样的 )
select e.* from employees e,dept_emp d where d.emp_no=e.emp_no and d.dept_no='d005'
查询结果85707条,查询时间0.294s,速度快乐很多嘛
查看执行计划
explain EXTENDED select e.* from employees e,dept_emp d where d.emp_no=e.emp_no and d.dept_no='d005';
1 SIMPLE d ref PRIMARY,emp_no,dept_no dept_no 12 const 149978 100 Using where; Using index1 SIMPLE e eq_ref PRIMARY PRIMARY 4 employees.d.emp_no 1 100
做个试验,调换下where的顺序,看看mysql是否会自动优化
执行下面的执行计划
explain EXTENDED select e.* from employees e,dept_emp d where d.dept_no='d005' and d.emp_no=e.emp_no ;
1 SIMPLE d ref PRIMARY,emp_no,dept_no dept_no 12 const 149978 100 Using where; Using index1 SIMPLE e eq_ref PRIMARY PRIMARY 4 employees.d.emp_no 1 100
执行计划是一样的,看来mysql内部的优化器已经自动做了优化
再换一种写法,看看能否优化,使用一张临时表
select e.* from employees e ,(SELECT emp_no FROM `dept_emp` where dept_no='d005') t where t.emp_no=e.emp_no;
执行时间0.26s,共85707条结果
查看执行计划
EXPLAIN EXTENDED select e.* from employees e ,(SELECT emp_no FROM `dept_emp` where dept_no='d005') t where t.emp_no=e.emp_no;
1 PRIMARYALL 85707 100 1 PRIMARY e eq_ref PRIMARY PRIMARY 4 t.emp_no 1 100 2 DERIVED dept_emp ref dept_no dept_no 12 149978 100 Using where; Using index
6 like的优化【优化※※】
mysql中貌似对like的话的索引支持不好,所以对大表一个字段做like操作的话,即使做了索引页不定会走到
直接上实验结果
explain SELECT * FROM `employees` where first_name = 'Guoxiang';
employees表上的firstname是有个一索引的,看执行计划也是可以走到索引的
1 SIMPLE employees ref index_firstName index_firstName 44 const 255 Using where
如果like的是全字段,或者like字段的后半部分貌似都能走到索引。。。
explain SELECT * FROM `employees` where first_name like 'Guoxiang';
1 SIMPLE employees range index_firstName index_firstName 44 255 Using where
explain SELECT * FROM `employees` where first_name like 'Guo%';
1 SIMPLE employees range index_firstName index_firstName 44 503 Using where
如果是查询前半个字段就不行了
explain SELECT * FROM `employees` where first_name like '%xiang';
1 SIMPLE employees ALL 300473 Using where
对于like的解决方案,网上倒是有些说法
MYISAM引擎 英文的直接全文索引-中文的分词索引,用以取代LIKE
就是新建一个字段,存储原是字段的反向内容,然后搜索时,就可以倒过来搜索了。例如: like '%str‘ 可以改成like 'rts%'
总结一下,子查询的效率不高,一般可以用多表连接的来替换一下以提高效率。like也不是不走索引的,但是like前置部分是不走索引的,需要用全文索引或者倒置查询来替换下jiej