sql 优化
避免使用
select *用 union all 代替 union
小表驱动大表
in 适用于左边大表,右边小表。
exists 适用于左边小表,右边大表。
批量操作代替 for 循环,并进行分批次处理
多用 limit,比如 limit 1;
用连接查询代替子查询
join 的表不宜过多,不应该超过3个
join 时注意,能用
inner join的地方,尽量少用left join,因为inner join会自动小表驱动大表
高效的分页,利用索引,比如最大 id 范围查询(要求id连续且有序),或者使用 between(要求在唯一索引上分页,否则会出现每页大小不一致的问题)
select id,name,age from user limit 1000000,20;
优化1
select id,name,age from user where id > 1000000 limit 20;
优化2
select id,name,age from user where id between 1000000 and 1000020;
索引优化
正确加索引
使用 explain 命令,查看执行计划(索引失效场景)
mysql 会选错索引,可以使用
force index来强制查询sql走某个索引。
索引失效情况
表达式计算(+、-、*、/)、函数、类型转换(字符串字段匹配没有用引号括起来)导致索引失效
范围条件右边的列索引失效
不等于(!=或者<>)索引失效
like 以通配符 % 开头(左模糊,全模糊)索引失效
OR 前后存在非索引的列,索引失效
联合索引,查询条件列不是联合索引中的第一个列,索引失效
is null 可以使用索引,is not null 无法使用索引
in 可能会不走索引(比如
IN列表中的值过多), not in 可能走索引(比如 覆盖索引)
explain
1.id 列
select 的序列号,有几个 select 就有几个id,并且id的顺序是按 select 出现的顺序增长的。MySQL将 select 查询分为简单查询(SIMPLE)和复杂查询(PRIMARY)。
复杂查询分为三类:简单子查询、派生表(from语句中的子查询)、union 查询。
id列越大执行优先级越高,id相同则从上往下执行,id为NULL最后执行
2. select_type 列
表示对应行是简单还是复杂的查询,如果是复杂的查询,又是上述三种复杂查询中的哪一种。
1)simple:简单查询。查询不包含子查询和union
2)primary:复杂查询中最外层的 select
3)subquery:包含在 select 中的子查询(不在 from 子句中)
4)derived:包含在 from 子句中的子查询。MySQL会将结果存放在一个临时表中,也称为派生表
3.table 列
表示 explain 的一行正在访问哪个表
4.type 列
表示关联类型或访问类型,即MySQL决定如何查找表中的行,查找数据行记录的大概范围。
依次从最优到最差分别为:system > const > eq_ref > ref > range > index > ALL
一般来说,得保证查询达到 range级别,最好达到 ref
NULL:mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。例如:在索引列中选取最小值,可以单独查找索引来完成,不需要在执行时访问表
const, system:mysql能对查询的某部分进行优化并将其转化成一个常量(可以看show warnings 的结果)。用于 primary key 或 unique key 的所有列与常数比较时,所以表最多有一个匹配行,读取1次,速度比较快。system是const的特例,表里只有一条元组匹配时为system
eq_ref:primary key 或 unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录。这可能是在 const 之外最好的联接类型了,简单的 select 查询不会出现这种 type。
ref:相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。
range:范围扫描通常出现在 in(), between ,> ,<, >= 等操作中。使用一个索引来检索给定范围的行
index:扫描全表索引,这通常比ALL快一些。(index是从索引中读取的,而all是从硬盘中读取)
ALL:即全表扫描,意味着mysql需要从头到尾去查找所需要的行。通常情况下这需要增加索引来进行优化了
5.possible_keys 列
查询可能使用哪些索引来查找。
6.key 列
显示mysql实际采用哪个索引来优化对该表的访问。
如果没有使用索引,则该列是 NULL。
7.key_len 列
显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。
key_len计算规则如下:
字符串
char(n):n字节长度
varchar(n):2字节存储字符串长度,如果是utf-8,则长度 3n+ 2
数值类型
tinyint:1字节
smallint:2字节
int:4字节
bigint:8字节
时间类型
date:3字节
timestamp:4字节
datetime:8字节
如果字段允许为 NULL,需要1字节记录是否为 NULL
索引最大长度是768字节,当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。
8.ref 列
显示在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),字段名(例:film.id)
9.rows 列
mysql 估计要读取并检测的行数,注意这个不是结果集里的行数。
10.Extra 列
额外信息:
Using index:查询的列被索引覆盖,并且where筛选条件是索引的前导列,是性能高的表现。一般是使用了覆盖索引((索引包含了所有查询的字段)。
Using where:查询的列未被索引覆盖,where筛选条件非索引的前导列
Using where Using index:查询的列被索引覆盖,并且where筛选条件是索引列之一但是不是索引的前导列,意味着无法直接通过索引查找来查询到符合条件的数据
NULL:查询的列未被索引覆盖,并且where筛选条件是索引的前导列,意味着用到了索引,但是部分字段未被索引覆盖,必须通过“回表”来实现,不是纯粹地用到了索引,也不是完全没用到索引
Using index condition:与Using where类似,查询的列不完全被索引覆盖,where条件中是一个前导列的范围;
Using temporary:mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。
Using filesort:mysql 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。此时mysql会根据联接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下一般也是要考虑使用索引来优化的。