|
2.实战案例1:
问题语句运行超过5s:
SELECT `branch`.`id`, `branch`.`name`, `branch`.`registered_time`, `branch_region`.`region_id`, `user`.`username`, `user`.`mobile`, count(o.order_id) as order_num
FROM (`branch`)
LEFT JOIN `user` ON `user`.`branch_id` = `branch`.`id`
LEFT JOIN `branch_role` ON `branch_role`.`id` = `user`.`role_id`
LEFT JOIN `branch_region` ON `branch_region`.`branch_id` = `branch_role`.`branch_id`
LEFT JOIN `orders` o ON `branch`.`id` = `o`.`supplier_id`
WHERE branch.id NOT IN (select supplier_id from signing where seller_id=6683 and status < 6)
AND `branch`.`group` = 'SUPPLIER'
AND `branch_role`.`flag` = 'ADMINISTRATOR'
AND `branch`.`status` = 'NORMAL'
GROUP BY `branch`.`id`
ORDER BY `branch`.`registered_time` desc
LIMIT 20;
使用explain查看执行计划:
Mysql语句优化的原则——让你写sql更加顺手
根据“读取尽可能少的数据”的原则,发现读取行数最多的步骤读取了4792行。进而发现这个步骤没有用到索引(NULL)。而这个没有用索引的表是orders的supplier_id列。
加索引试试看:
alter table orders add index(supplier_id);
再次使用explain查看执行计划:
Mysql语句优化的原则——让你写sql更加顺手
可以看到这个步骤使用了索引,读取的行数减少到了599行。
实际执行一下,秒出。
3.explain执行计划各个字段的意义:
1)id:语句的执行顺序,倒序执行
2)select_type:主要有以下几个类型:
lsimple:表示简单的select,没有union和子查询
lprimary:最外层的select。在有子查询的语句中,最外面的select查询就是primary
lunion:union语句的第二个或者说是后面那一个
lunion result:union的结果
lsubquery: 子查询中的第一个 select
3)table:涉及的表。
4)type:连接类型。主要有以下几个:(重点查看)
lconst:说明只有一个匹配行,使用了主键或唯一性索引。通常是最优化的情况。
leq_ref,ref,ref_or_null:表示走了简单索引
lindex_merge:表示使用了多个索引的组合
lrange:表示通过索引取出了一个范围内的值。例如where a in (1,2)
lindex:表示对索引进行了全扫描
lALL:表示全表扫描
注意:以上类型从上到下性能越来越差。
5)possible_keys:可供使用的索引
6)keys:实际使用的索引
7)key_gen:索引长度
8)ref:显示使用哪个列或常数与索引一起从表中选择行
9)rows:读取的行数。(重点查看)
10)Extra:备注
|
|