时间:2021-07-01 10:21:17 帮助过:2人阅读
学到了几个不错的优化方法: 
1、技术优化 
   在网上有不少对SQL本身优化的方法,如建立索引并确保合理有效使用上索引,分析执行计划,在基于代价执行场景下,通过执行计划不是高手很难分析出问题(慢慢学习吧~)。 
2、业务优化 
1)明确查询主表再left join查询辅助列,from MainTabel m,m中包括整个sql返回结果的全部行; 
A表的ID取前10然后再取B表的name 
select T.,B.name from (select  from A order by a.id limit 10 ) T left join B on t.id = b.id 
2)去掉不必要的列和表; 
去掉列好说,去掉表别说不可能,见过不少,特别是用到数据量大的表进行关联取数据,没业务环境例子不那么好举。 
select tn.id,tn.cn, t1.c1,t2.c2,… from t1,t2,…,tn where … and tn.id = ‘100’ and tn.cn = ‘cn’ 
考虑不使用tn表,查询列用到tn的两个列如果非得加在sql里可以写成select ‘100’ id, ‘cn’ cn, … from … 
去掉不必要的表优化效果非常明显,前提是得较深入了解业务。 
3)利用子查询限定数据范围; 
select * from t1,t2,…,tn条件全部在where中 
实际上用到t2表仅有一条记录,过多的条件关联未能确保对于记录少的表优先处理,可以考虑 
select * from t1,(select * from t2 where t2条件),…,tn 
4)子查询未加条件导致范围过大; 
select t1.c1,t1.c2,t2.cnt 
  from t1,(select c3,max(c4) cnt from t1 group by c3) t2 
 where t1.c3 = t2.c3 
   and t1.id1 = ? and t1.id2 = ? 
在t2子查询中group by的是整个t1表数据,实际只需要对id1和id2为特定值的数据进行分组,在子查询中加上条件。 
5)创建临时表或使用with语法; 
with w_tab as 
(select from t1,t2,t3) 
select from w_tab m, w_tab a 
6)优化count()、min()、max() 
min() :如果使用min()函数的数据列创建了索引,那么查询在O(1)的时间内完成,B-tree可以直接找最左端的数据。同理,max()直接找最右端的数据返回 
count():没有where条件的count对于myisam存储引擎来说是很快的,因为在myisam引擎中维护了一个变量来存储行数 
7)优化order by,使用索引扫描来做排序 
order by 的列要满足最左索引,也可以跟where条件同时使用来满足最左索引 
条件: 1)最左索引,不能跳跃 
     2)顺序跟索引顺序一致 
3)排序顺序要一致,不能一个升序一个降序 
示例: 
CREATE TABLE pro_subgroup ( 
  pro_subgroup_id int(10) NOT NULL AUTO_INCREMENT  
  pro_subgroup_name varchar(50) NOT NULL DEFAULT ”  
  pro_group_id int(10) NOT NULL DEFAULT ‘0’  
  PRIMARY KEY (pro_subgroup_id), 
  KEY name_id (pro_subgroup_id,pro_subgroup_name,pro_group_id) 
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8 
EXPLAIN SELECT * FROM pro_subgroup ps 
ORDER BY ps.pro_subgroup_id DESC, ps.pro_group_id DESC 
Using index; Using filesort  
跳跃未使用索引 
 8)使用覆盖索引。覆盖索引就是查询的列是全部的索引或部分索引列。使用覆盖索引的好处就是不需要回表再取其他列数据,直接使用索引查询就能返回结果,查询效率会提高很多。 
对于innodb存储引擎而言,主键索引是聚集索引,聚集索引在叶子结点上保存了行的其他信息。二级索引在叶子结点上保存了行了主键值。如果在innodb上不使用覆盖索引,那么在需要先遍历二级索引,找到相应的主键值,然后再从主键查找其他列的信息。而使用覆盖索引就可以直接返回索引查询到的信息。 
对于myisam来说,myisam的索引文件时存在内存中的,数据文件时放在磁盘中的。如果使用覆盖索引相当于是只访问内存数据,不用去磁盘查找。所以效率也是相当好的。 
查询全部的索引列,可以使用覆盖索引 
Key(name) 
EXPLAIN SELECT NAME FROM user_admin 
 
注意使用覆盖索引时,查询的列必须在一个索引集里面。比如单独给name和password创建了两个索引。此时select  name,password from table是无法使用覆盖索引的 
查询列不在一个索引集里,无法使用覆盖索引 
Key name(name) 
Key password (‘password’) 
EXPLAIN SELECT NAME,PASSWORD FROM user_admin 
 
查询列为索引的一部分,可以使用覆盖索引 
Key name_password (name,password) 
EXPLAIN SELECT NAME FROM user_admin 
 
查询全部的列 
EXPLAIN SELECT * FROM user_admin WHERE NAME=’admin’ AND PASSWORD =”  
 
Using index condition :必要的时候查看是否需要全表扫描,因为select * 还是要读到表数据的,但是使用了索引。 
优化 
EXPLAIN SELECT * FROM user_admin a JOIN (SELECT admin_id FROM user_admin WHERE NAME=’admin’ AND PASSWORD =”) b  
ON a.admin_id = b.admin_id 
 
没有优化 
继续。。 
修改key:  
alter table modify key name_password_email id_name_password(‘admin_id’,’name’,’password’) 
EXPLAIN SELECT * FROM user_admin a JOIN (SELECT admin_id FROM user_admin WHERE NAME=’admin’ AND PASSWORD =”) b  
ON a.admin_id = b.admin_id 
 
终于可以了,子查询使用覆盖索引,然后对查询出的结果再与主表进行连接查询其他列数据 
如果表使用的引擎是innoDB,那么可以有效的利用主键进行覆盖索引查询。因为二级索引的叶子结点保存了主键值 
EXPLAIN SELECT admin_id,NAME FROM user_admin  WHERE NAME=” 
 
优化总则: 
1)索引优化 
正确的使用索引 
2)查询需要的数据n 
innodb引擎的话where条件中有主键时可以直接使用select *,因为innodb的主键中存储了其他列信息,如果不含主键在查询时尽量只查询需要的字段。 
3)切分查询 
切分查询是将一个查询分多次执行。比如一次较大的delete可以分几次来执行 
4)分解关联查询 
分解关联查询就是将一个大的关联查询分解为多个小的查询,一次查询出一部分数据,可以有效的使用缓存。但是不一定是所有的查询都要进行分解,因为分解后的查询语句可读性不强,对于以后的维护会有一定的困难。
总结:优化查询语句需要从几方面入手考虑: 
1、  减少数据访问(减少磁盘访问) 
2、  返回更少数据(减少网络传输或磁盘访问) 
3、  减少交互次数(减少网络传输) 
4、  减少服务器CPU开销(减少CPU及内存开销) 
5、  利用更多资源(增加资源)
MySQL—SQL优化
标签: