有些时候,我们经常会改写一些SQL,通过牺牲SQL的可读性来优化SQL的执行速度,但是大部分情况下,我们这么做是多余的,而且是不可取的,因为MySQL自身就完成了这项工作所以,我们需要多了解了解MySQL本身是如何进行SQL改写工作的

1、去掉不必要的括号

((a AND b) AND c OR (((a AND b) AND (c AND d))))
->
(a AND b AND c) OR (a AND b AND c AND d)

2、常量替换

a > b and a = c and b = 5
->
a > 5 and a = c and b = 5

3、条件移除

(B>=5 AND B=5) OR (B=6 AND 5=5) OR (B=7 AND 5=6)
->
B = 5 OR B = 6

4、应用在索引上的常量表达式,只计算一次

5、MYISAM和MEMORY表,不带where条件的count(*)是直接从MYSQL内部的元数据表中返回结果的,注意,innodb不是!该法则同样适用于一张表上的某列的where is not null的查询

6、尽早的检测出不可能满足条件的where语句,并直接返回空,比如:where 0 > 1

7、当查询语句中不包含gourp by 或者其他的聚合函数(sum,count)时,having语句将合并到where条件中,但是这里注意的是,执行计划并不等同于将having部分直接写到where条件中去,比如如下SQL:
select * from bigtable where ID > 200000 and ID < 400000000000 having id = 9;
select * from bigtable where ID > 200000 and ID < 400000000000 and id = 9;

其结果是一样的,返回空,但是使用explain的结果是不一样的,having的explain是使用索引的区间扫描,而后者直接定位为不可能的where条件(参考第6条件)

8、在多表join时,所有"常量表"将会被优先读取,所谓"常量表",就是指“记录非常少的表”,这样其在优先读取的时候,做join就是小表驱动大表,性能自然优化上去了。“常量表实例”:
空表或者只有一行记录的表;
主键索引或者唯一索引,并且索引中的所有列,都定义为not null,并且其在where条件中是与一个常量进行比较,比如下面查询中的所有表(t, t1, t2),都是“常量表”:
SELECT * FROM t WHERE primary_key=1;
SELECT * FROM t1,t2
  WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
实战:
one_row_table 有一行记录,id为主键,int2f无索引,int3f为唯一索引,如下两个查询:

mysql> explain select * from bigtable bt join one_row_table one on bt.id = one.id where one.<span style="color:#ff0000;">int2f</span> = 1;
+----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref         | rows | Extra       |
+----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------------+
|  1 | SIMPLE      | one   | ALL    | NULL          | NULL    | NULL    | NULL        |    1 | Using where |
|  1 | SIMPLE      | bt    | eq_ref | PRIMARY       | PRIMARY | 4       | test.one.id |    1 | NULL        |
+----+-------------+-------+--------+---------------+---------+---------+-------------+------+-------------+
mysql> explain select * from bigtable bt join one_row_table one on bt.id = one.id where one.<span style="color:#ff0000;">int3f</span> = 1;
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra                                               |
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | Impossible WHERE noticed <span style="color:#ff0000;">after reading const tables</span> |
+----+-------------+-------+------+---------------+------+---------+------+------+-----------------------------------------------------+




9、当多个表做join时,如果最终的order by 和group by 的所有列来自同一个表,优先考虑将该表放在join的最前面

10、如果order by和group by 的列不一样,或者order by 或 group by 的列并不来自第一个join的表,则临时表将会被创建

11、如果指定了SQL_SMALL_RESULT选项,则mysql将会使用内存临时表

12、现在的优化器在选择索引时将不是单一的考虑该索引的过滤性是否达到30%,而是综合了表的大小、行数、IO的块数等因素,综合考量得来

13、如果select中的列全部来自于索引,而且是数字类型,那么MYSQL将仅使用索引就能够返回查询结果,而不需要再去查阅数据文件

14、MYSQL在最终输出每一行数据时,将会做having判断,不满足条件的行,将会被跳过