一.MYSQL DB SQL优化的目标

a.减小IO次数

IO是关系型DB最大的瓶颈,减小IO次数是最有效和最重要的途径。

how?

1.充分利用索引,避免全表扫

2.高效利用内存,减少子查询的滥用

FlashCache 利用SSD随机读高效性,来缓存热数据,没内存快,但可以比内存大的多;

b.减少CPU计算

当我们的IO优化到一定阶段,就要考虑再来降低CPU的计算

how?

避免或减少order by ,group by ,distinct 操作(排序在内存中有比较操作)

二、SQL 优化原则

1.减少过多表的join操作

在设计上就要考虑适当的冗余。mysql 是简单高效的,对复杂的多表JOIN,其一优化器上有限制,其二功夫还不够,和ORACLE相比较还是有很大差距。

sort-merge join 无

hash join 无

Nested Loop Join 原理

通过驱动表的结果集作为循环基础数据,然后一条一条的通过该结果集中的数据作为过滤条件到下一个表中查询数据,然后合并结果。如果有多个join,则将前面的结果集作为循环数据,再一次作为循环条件到后一个表中查询数据。

for each record A.* in table tb_A (where tb_A.col1=value){
for each record B.* in tb_B that B.col1=A.col1{
for each record C.* in tb_C that C.col1=B.col1
pass the (A.col1, B.col2, C.col3) row
combination to output;
}
}

使用JOIN BUFFER缓冲,ALL,index,range时会出现

for each record A.* in table tb_A{
for each recordB.* in tb_B that A.col1=B.col1{
put (A.col1, B.col2) into the buffer
if (buffer is full)
flush_buffer();
}
}
flush_buffer(){
for each record C.* in tb_Cthat C.col1 = B.col1{
for each record in the buffer
pass (A.col1, B.col2, C.col3) row combination to output;
}
empty the buffer;
}

STRAIGHT_JOIN 使用 强制改变表联接顺序

2. 尽量少用子查询

MYSQL对子查询的优化不足,且一直没有修正。

可尝试改子查询为JOIN操作。

此外子查询会使用临时表存储中间结果集,子表用不上索引会进一步导致效率问题!

3.尽量提前过滤

把区分度高的条件写在最前面(SQL的书写最好也这样干),LEFT JOIN时把小表放在前面做为驱动表

4.尽量少用in子句,常出现子查询

a.in (1,2,...,3333) 大量列值会有严重的效率问题

尝试使用临时表来JOIN操作

尝试改写成union all 操作(有限少量)

b.in (select id from tb_a)

尝试改成JOIN操作

尝试使用exists替代(不一定会提高效率,关键要看exists有没有使用到索引)

5.尽量少用or操作

可使用UNION ALL 来替换,union all 效率一般会高很多

6.尽量使用union all 而不是union

union 有对结果集(合并后的结果集)排序去重,请确定是否有去此逻辑需求,可以有效降低CPU计算

7.尽量少排序

尽量利用索引进行排序,有时候SQL过于复杂,用不上也木办法,排序会消耗较多CPU资源;

可以通过利用索引来排序的方式进行优化

减少参与排序的记录条数

非必要不对数据进行排序

8. 尽量避免使用select *

多数不会有效率影响

但对输出结果只包含在索引中的结果集,含有排序操作的,会增加IO

9.尽量避免类型转换

表设计的时候,多表同一个字段类型要保证一致

因为在多表关联时,关联字段无法使用索引

类型不同、字符集不同会使索引失效

隐含类型转换: 输入转形参类型,转return 类型, 转变量定义类型

一些误区:

1.count(1)和count(primary_key) 优于 count(*)

有时会更慢,原因数据库对 count(*) 计数操作做了一些特别的优化。

注意:select count(col1) 和select count(*) 的逻辑区别

2. select col1,col2 from … 比 select col1,col2,col3 from …

可以让数据库访问更少的数据量

MYSQL 读取数据是以PAGE为单位,每个PAGE至少要存2行,每行都是存储了该行的所有字段或一部分(lob等特殊类型字段除外)。

不过这样干是个好习惯!

3. order by 一定会排序操作

如果ORDER BY子句能利用上索引,就没必要再做排序

order by 后的字段升降序一致,且包含在goup by后面,不用在额外排序(group by 内部有做排序)

DISTINCT 是group by 的一个特例

group by a,b order by null 最终结果集不排序

4.执行计划中有 filesort 就会进行磁盘文件排序

写法问题,这个只表明有排序操作

三、现存问题

1.子查询的滥用

逻辑清晰,效率低下!

2.in 子句的滥用

全表扫效率低下!建临时表JOIN操作 或 尝试使用 exists代替

3.or 子句的滥用

尝试使用UNION ALL去修改

是否有法子可以避免

4.超多表JOIN

SQL超级复杂

提前过滤相关数数

计数时可精简掉不必要的表及子句

5.逻辑上的冗余

了解数据的组成,充分利用数据本身的结构来精简逻辑

6.表设计上的不合理

提倡适当的冗余!

7.SQL超级复杂

提倡简单高效的SQL语句组合,而非一句SQL搞定一切