看了很多如果优化SQL语句的文章,总结起来这些优化无非有三个最最重要的目的。
第一个目的,让SQL语句能够高效正确的使用索引,避免因为SQL语句的不当造成mysql数据库本身放弃使用索引而进行全表扫描。
第二个目的,减少数据库操作的IO开销,提高数据库的处理速度。
第三个目的,使得过分复杂的SQL语句简洁化,有利于代码的维护。
通常大多数的优化工作都是为了第一个目的,为了让查询语句可以正确的使用索引。有时候一些初级的工程师虽然在数据表上添加了索引,可是由于对如何正确使用索引的认识不足。写出来的查询语句根本没有使用到所添加的索引,导致程序执行效率很低。
比如有一张学生表,有id,name,class,age,gender等字段,工程师分别在id和name上添加了索引。可查询语句的查询条件却没有使用到这两个中任何一个索引字段。比如select * from student where age=12 order by class这条语句将导致使用全表扫描,效率相当低下。
或者使用了这条语句select * from student where name !="小明",虽然name字段上添加了索引,但数据库仍然会使用全表扫描。
又如select * from student where name is null,这也将导致全表扫描,好的做法是给字段添加is not null属性并添加默认值。
下面一些情况也会让引擎放弃索引使用全表扫描:
1.在 where 子句中使用 or 来连接条件
2.(不能前置百分号)
select * from student where name like ‘%abc%’
若要提高效率,可以考虑全文检索
3.in 和 not in 也要慎用,否则会导致全表扫描,如:
select id from student where num in(1,2,3)
对于连续的数值,能用 between 就不要用 in 了:
select id from t where num between 1 and 3
4.在where子句中使用参数 入 set $id=1;select * from student where id=$id
5.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描select * from student where id*3=27
6.应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描
7..不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引
8.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使 用,并且应尽可能的让字段顺序与索引顺序相一致
9.并不是所有索引对查询都有效,SQL是根据表中数据来进行查询优化的,当索引列有大量数据重复时,SQL查询可能不会去利用索引,如一表中有字段 sex,male、female几乎各一半,那么即使在sex上建了索引也对查询效率起不了作用
对于第二个目的,就是主要避免像select * 这样的语句,根据实际情况的需要去选择应用需要的数据,避免垃圾数据的读取,而且减少数据在网络上传输的开销。还有就是尽可能避免使用临时表或是游标,因为这建立和销毁临时表都需要开销,增加数据库运行负担,而游标的运行效率很低,切创建和销毁游标也需要一定的开销。
而对于最后一个目的,主要是为了方便日后阅读和维护代码,试想,如果一条SQL语句有一个页面这么长,谁能很轻易的看的懂。而且特别复杂的SQL语句很容易隐藏不容易被发现的错误,而且不容易排查,而且这错误很可能是致命的,而且特别复杂的SQL语句本身执行效率一定不会高。所以,针对这种特别复杂的SQL语句,最好的办法是将其拆分成一段段小的方便维护的SQL语句,可以用其他语句如PHP去处理他们产生的中间结果,最后达到跟一条SQL语句相同目的的结果集。且MYSQL并发处理多个小语句的效率比一次处理一条复杂语句的效率要高很多。即便是拆分后的语句执行效率略低于一条SQL,但从方便维护的角度来说也是多条比一条要好很多。