一个mysql比较典型的子查询改join优化

一个mysql比较典型的子查询改join优化

早些年当作sql server /orcal sql的dba,后来进入互联网用mysql比较高,早年各项目重度依赖sql

近年几搞大数据,mysql也是用,不涉及优化,整体mysql在行业内是被弱化了的,因为针对各场景的其他sql/nosql组件可以选择

量不大,不用优化,会读写就可以了。量大,换别的方案,而对sql的优化很少有像早期有专值的DBA 针对性的维护和操作

最近业务方的数据慢查询提到了我这里,建议能不能抽空作点优化

这又算是老本行了,就协助简单优化了一部分

其实很多慢查询优化,说白了是mysql的问题,mysql的查询优化相比orcal和sql server 作的太差 不得不用一些很难看的技巧来适配mysql低下的处理能力

表结构就不放了
只放sql和查询计划

重点是把子查询去掉,替换为join结构

原始查询计划

explain SELECT
ed_set_interval, s.seed_set_status, s.creator_id, s.created_at, s.updated_at, s.expired_at, s.is_fulled, u.username, u.user_email d_set_platform, s.seed_set_price, s.se
    -> FROM
    -> sms_seed_set s
    -> LEFT JOIN sms_user u
    -> ON s.creator_id = u.id
    -> LEFT JOIN
    -> (SELECT sms_seed_set_id, count(*) AS count FROM sms_seed WHERE is_deleted = 'NO' GROUP BY sms_seed_set_id) AS ssc
    -> ON s.id = ssc.sms_seed_set_id
    -> WHERE ( s.is_deleted = 'NO' ) order by id desc LIMIT 20;
+------+-------------+------------+--------+---------------+-------------------------+---------+-----------------------+---------+--------------------------+
| id   | select_type | table      | type   | possible_keys | key                     | key_len | ref                   | rows    | Extra                    |
+------+-------------+------------+--------+---------------+-------------------------+---------+-----------------------+---------+--------------------------+
|    1 | PRIMARY     | s          | index  | NULL          | PRIMARY                 | 4       | NULL                  |       1 | Using where              |
|    1 | PRIMARY     | u          | eq_ref | PRIMARY       | PRIMARY                 | 4       | sms_test.s.creator_id |       1 |                          |
|    1 | PRIMARY     | <derived2> | ref    | key0          | key0                    | 5       | sms_test.s.id         |   14223 | Using where              |
|    2 | DERIVED     | sms_seed   | index  | NULL          | idx_seed_set_is_deleted | 6       | NULL                  | 1422360 | Using where; Using index |
+------+-------------+------------+--------+---------------+-------------------------+---------+-----------------------+---------+--------------------------+

优化后

explain SELECT ifnull(count(*),0) as seedCount,s.id, s.seed_set_source, s.seed_set_name, s.seed_set_description, s.seed_set_type, s.seed_set_platform, s.seed_set_price, s.seed_set_interval, s.seed_set_status, s.creator_id, s.created_at, s.updated_at, s.expired_at, s.is_fulled, u.username, u.user_email  FROM sms_seed ssc  LEFT JOIN sms_seed_set s ON ssc.sms_seed_set_id =s.id
LEFT JOIN sms_user u ON s.creator_id = u.id 
WHERE ( s.is_deleted = 'NO' and ssc.is_deleted = 'NO') 
GROUP BY sms_seed_set_id order by s.id desc LIMIT 20;

+------+-------------+-------+--------+-------------------------+-------------------------+---------+-----------------------+------+----------------------------------------------+
| id   | select_type | table | type   | possible_keys           | key                     | key_len | ref                   | rows | Extra                                        |
+------+-------------+-------+--------+-------------------------+-------------------------+---------+-----------------------+------+----------------------------------------------+
|    1 | SIMPLE      | s     | ALL    | PRIMARY                 | NULL                    | NULL    | NULL                  |   21 | Using where; Using temporary; Using filesort |
|    1 | SIMPLE      | u     | eq_ref | PRIMARY                 | PRIMARY                 | 4       | sms_test.s.creator_id |    1 |                                              |
|    1 | SIMPLE      | ssc   | ref    | idx_seed_set_is_deleted | idx_seed_set_is_deleted | 6       | sms_test.s.id,const   | 4063 | Using where; Using index                     |
+------+-------------+-------+--------+-------------------------+-------------------------+---------+-----------------------+------+----------------------------------------------+

隐约记得mysql有个索引应用优先级的的问题,通过调整sql把大表的索引优先级调高,我习惯把大表提前

从技术角度以上优化已经完成任务,但又要结合业务,业务对每个sql是有主副表的,要求再调下join几张表的先后顺序,把大表调后

验证下调整table顺序后的查询计划是否变更,结果一致

explain SELECT ifnull(count(*),0) as seedCount,s.id, s.seed_set_source, s.seed_set_name, s.seed_set_description, s.seed_set_type, s.seed_set_platform, s.seed_set_price, s.seed_set_interval, s.seed_set_status, s.creator_id, s.created_at, s.updated_at, s.expired_at, s.is_fulled, u.username, u.user_email  
FROM sms_seed_set s  LEFT JOIN sms_seed ssc ON ssc.sms_seed_set_id =s.id
LEFT JOIN sms_user u ON s.creator_id = u.id 
WHERE ( s.is_deleted = 'NO' and ssc.is_deleted = 'NO') GROUP BY sms_seed_set_id order by s.id desc LIMIT 20;
+------+-------------+-------+--------+-------------------------+-------------------------+---------+-----------------------+-------+----------------------------------------------+
| id   | select_type | table | type   | possible_keys           | key                     | key_len | ref                   | rows  | Extra                                        |
+------+-------------+-------+--------+-------------------------+-------------------------+---------+-----------------------+-------+----------------------------------------------+
|    1 | SIMPLE      | s     | ALL    | PRIMARY                 | NULL                    | NULL    | NULL                  |    23 | Using where; Using temporary; Using filesort |
|    1 | SIMPLE      | u     | eq_ref | PRIMARY                 | PRIMARY                 | 4       | sms_test.s.creator_id |     1 |                                              |
|    1 | SIMPLE      | ssc   | ref    | idx_seed_set_is_deleted | idx_seed_set_is_deleted | 6       | sms_test.s.id,const   | 78177 | Using where; Using index                     |
+------+-------------+-------+--------+-------------------------+-------------------------+---------+-----------------------+-------+----------------------------------------------+
posted @ 2021-02-28 17:32  cclient  阅读(366)  评论(0编辑  收藏  举报