目录
目的
目标
explain
优化
避免使用select *
用union all代替union
小表驱动大表(in与exists)
批量操作
多使用limit
in中值太多
不使用%前缀模糊查询
不在where子句中进行表达式操作
避免隐式类型转换
联合索引遵守最左前缀法则
inner join、left join、right join、full join
count(*)与count(1)
避免is null /is not null
避免在 where 子句中使用 or
去重distinct过滤字段要少
目的
1.提高资源的利用率
2.提高系统的吞吐量
3.同时满足更多用户的在线需求
目标
1.减少磁盘IO
2.减少网络带宽
3.降低cpu消耗
explain
在select语句之前增加explain关键字,执行后MySQL就会返回执行计划的信息,而不是执行sql。但如果from中包含子查询,MySQL仍会执行该子查询,并把子查询的结果放入临时表中。
EXPLAIN SELECT
tp.*, col.course_title couserName,
col.course_type_name courseName,
col.course_theme_name courseTheme,
col.course_type_name courseType
FROM
le_teaching_plan tp
JOIN le_course col ON tp.course_id = col.id
WHERE
tp.id = '0293abd864954d4b93f163e473924032'
1.id:id列的编号是select的序列号,有几个select就有几个id
2.select_type:
simple:不包含子查询和union的简单查询
primary:复杂查询中最外层的select
subquery:包含在select中的子查询
derived:包含在from子句中的子查询
union:在union中的第二个和随后的select,UNION RESULT为合并的结果
3.table:表示当前行访问的是哪张表
4.partitions:查询将匹配记录的分区,对于非分区表为null
5.type:此列表示关联类型或访问类型。也就是MySQL决定如何查找表中的行。依次从最优到最差分别为:system > const > eq_ref > ref > range > index > all
6.possible_keys:此列显示在查询中可能用到的索引
7.key:此列显示MySQL在查询时实际用到的索引
8.key_len:索引里使用的字节数
9.ref:显示key列记录的索引中,表查找值时使用到的列或常量
10.rows:查询中估计要读取的行数
11.Extra:额外信息
优化
避免使用select *
使用*号多查出来的数据,通过网络IO传输的过程中,也会增加数据传输的时间;同时*不走覆盖索引,导致性能降低。
通过索引值可以直接找到要查询字段的值,而不需要通过主键值回表查询,那么就叫覆盖索引。
用union all代替union
(select * from user where id=1)
union
(select * from user where id=2);
使用union关键字后,可以获取排重后的数据(排重的过程需要遍历、排序和比较,它更耗时,更消耗cpu资源)
使用union all关键字,可以获取所有数据,包含重复的数据
小表驱动大表(in与exists)
用小表的数据集驱动大表的数据集
select * from order
where user_id in (select id from user where status=1)与
select * from order
where exists (select 1 from user where order.user_id = user.id and status=1)
sql语句中包含了in关键字,则它会优先执行in里面的子查询语句,然后再执行in外面的语句。
sql语句中包含了exists关键字,它优先执行exists左边的语句(即主查询语句)。然后把它作为条件,去跟右边的语句匹配。如果匹配上,则可以查询出数据。如果匹配不上,数据就被过滤掉了。
in 适用于左边大表,右边小表;exists 适用于左边小表,右边大表。
批量操作
尽量只远程请求一次数据库,sql性能会得到提升,数据量越多,提升越大;需要注意的是,不建议一次批量操作太多的数据,如果数据太多数据库响应也会很慢。批量操作需要把握一个度,建议每批数据尽量控制在500以内。如果数据多于500,则分多批次处理
多使用limit
为了使explain中type列达到const类型。当只需要一条数据的时候,使用limit 1,如果加上limit1,查找到就不用继续往后找了
in中值太多
select id,name from category
where id in (1,2,3...100000000);
不使用%前缀模糊查询
select * from order where name like '%name%'
使用%前缀会导致索引失效而进行全表扫描;
如果需要使用%name%,可以使用全文索引
创建全文索引
alter table order add fulltest index `idx_name` (`name`);
使用全文索引
select * from order where match(name) against('zhangsan')
不在where子句中进行表达式操作
select user_id,user_project from user_base where age*2=36;
字段就行了算术运算,这会造成引擎放弃使用索引
避免隐式类型转换
where子句中出现name字段的类型和传入的参数类型不一致的时候发生的类型转换,会导致索引失效
联合索引遵守最左前缀法则
如含有字段id、name、school,可以直接用id字段,也可以id、name这样的顺序,但是name;school都无法使用这个索引。
联合索引存在范围查询,比如between、>、<等条件时,会造成后面的索引字段失效
inner join、left join、right join、full join
left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录
right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录
inner join(内连接) 返回两个表中联结字段相等的行
full join(全连接)返回两个表中没有相等的行
count(*)与count(1)
如果表中多个列并且没有主键,则count(1)的执行效率优于count(*);
如果有主键,则select count(主键)的执行效率是最优的;如果表中只有一个字段,则select count(*)最优。
避免is null /is not null
select id from t where num is null
尽量避免在 where 子句中对字段进行 null 值判断,使用is null 或者is not null 理论上都会走索引,存在Null值会导致mysql优化器处理起来比较复杂,容易导致引擎放弃使用索引而进行全表扫描
null值很难查询优化且占用额外的索引空间,推荐默认数字0代替null
避免在 where 子句中使用 or
select id from t where num=10 or num=20
改为:
select id from t where num=10
union all
select id from t where num=20
where 子句中使用 or来连接条件,否则将导致引擎放弃使用索引而进行全表扫描;如果要利用索引,则OR之间的每个条件列都必须要用到索引。
去重distinct过滤字段要少
当查询很多字段时,如果使用distinct,数据库引擎就会对数据进行比较,过滤掉重复数据,然而这个比较、过滤的过程会占用系统资源,如cpu时间