straight_join优化sql语句

在表关联查询中,mysql优化器往往会选择结果集小的表,但是往往也会有例外:
SELECT                                                                    ebt.relative_type,                                                ebt.relative_Id,                                                  bu.buyer_photo,                                                   ebt.`business_type`,                                              bu.email,                                                         bu.first_name,                                                    bu.last_name                                                               FROM                                                      `edm$business_task` ebt,                                          `edm$business_task_list` ebtl,                                    `buyer$user` bu,                                                  `edm$country_strategy` ecs                                                                         WHERE ebt.task_id = ebtl.task_id                                  AND ebt.business_type = ebtl.business_type                        AND bu.buyer_id = ebt.relative_id                                 AND ecs.country_id = bu.country_id                                AND ebt.business_type = 23                                       AND ebtl.exec_email = 0                                           AND ecs.delivery_time_point = '1:00'                              AND TIMESTAMPDIFF(DAY,ebtl.create_time, '2015-09-14' ) = 0;
执行时间需要三十秒
explain下,以ebt作为驱动表:
+----+-------------+-------+--------+--------------------------------------------------------+------------------------+---------+-----------------------+---------+-------------+
| id | select_type | table | type   | possible_keys                                          | key                    | key_len | ref                   | rows    | Extra       |
+----+-------------+-------+--------+--------------------------------------------------------+------------------------+---------+-----------------------+---------+-------------+
|  1 | SIMPLE      | ebt   | ref    | PRIMARY,index_business_task_rid,index_business_task_bt | index_business_task_bt | 5       | const                 | 3341380 | Using where |
|  1 | SIMPLE      | bu    | eq_ref | PRIMARY,idx_buyer$user_country_id                      | PRIMARY                | 4       | cfec1.ebt.relative_id |       1 | Using where |
|  1 | SIMPLE      | ebtl  | ref    | index_business_tl_tid,index_business_tl_bt             | index_business_tl_tid  | 5       | cfec1.ebt.task_id     |       1 | Using where |
|  1 | SIMPLE      | ecs   | ref    | fk_strategy_bt                                         | fk_strategy_bt         | 4       | cfec1.bu.country_id   |       1 | Using where |
+----+-------------+-------+--------+--------------------------------------------------------+------------------------+---------+-----------------------+---------+------------

查看ebt的结果集(ebt.business_type = 23)
mysql> select  count(*) from `edm$business_task` ebt where ebt.business_type =23 ;
+----------+
| count(*) |
+----------+
|  1749616 |
+----------+
1 row in set (0.87 sec)
ebt表竟然有100多万行记录,然后想办法缩小结果集
我们关注查询这样一些表达式:ebt.business_type = ebtl.business_type AND ebt.business_type = 23然后ebtl.exec_email = 0,TIMESTAMPDIFF(DAY,ebtl.create_time, '2015-09-14' ) = 0;
是否可以将ebtl作为关联表,ebt.business_type = 23改成ebtl.business_type=23来减少结果集呢?
看如下语句,结果集为22w的样子
mysql> SELECT count(*) FROM `edm$business_task_list` ebtl   WHERE  ebtl.business_type=23 AND ebtl.exec_email = 0  AND TIMESTAMPDIFF(DAY,ebtl.create_time, '2015-09-14' ) = 0;
+----------+
| count(*) |
+----------+
|   222669 |
+----------+
看来理论上还是可行了

改写sql语句如下:

mysql> SELECT                                                                    ebt.relative_type,                                                ebt.relative_Id,                                                  bu.buyer_photo,                                                   ebt.`business_type`,                                              bu.email,                                                         bu.first_name,                                                    bu.last_name                                                               FROM                                                      `edm$business_task` ebt,                                          `edm$business_task_list` ebtl,                                    `buyer$user` bu,                                                  `edm$country_strategy` ecs                                                                         WHERE ebt.task_id = ebtl.task_id                                  AND ebt.business_type = ebtl.business_type                        AND bu.buyer_id = ebt.relative_id                                 AND ecs.country_id = bu.country_id                                AND ebtl.business_type = 23                                       AND ebtl.exec_email = 0                                           AND ecs.delivery_time_point = '1:00'                              AND TIMESTAMPDIFF(DAY,ebtl.create_time, '2015-09-14' ) = 0;
Empty set (30.73 sec)

结果还是30秒
查看下执行计划:
mysql> explain SELECT                                                                    ebt.relative_type,                                                ebt.relative_Id,                                                  bu.buyer_photo,                                                   ebt.`business_type`,                                              bu.email,                                                         bu.first_name,                                                    bu.last_name                                                               FROM                                                      `edm$business_task` ebt,                                          `edm$business_task_list` ebtl,                                    `buyer$user` bu,                                                  `edm$country_strategy` ecs                                                                         WHERE ebt.task_id = ebtl.task_id                                  AND ebt.business_type = ebtl.business_type                        AND bu.buyer_id = ebt.relative_id                                 AND ecs.country_id = bu.country_id                                AND ebtl.business_type = 23                                       AND ebtl.exec_email = 0                                           AND ecs.delivery_time_point = '1:00'                              AND TIMESTAMPDIFF(DAY,ebtl.create_time, '2015-09-14' ) = 0;                                                                                            
+----+-------------+-------+--------+--------------------------------------------------------+------------------------+---------+-----------------------+---------+-------------+
| id | select_type | table | type   | possible_keys                                          | key                    | key_len | ref                   | rows    | Extra       |
+----+-------------+-------+--------+--------------------------------------------------------+------------------------+---------+-----------------------+---------+-------------+
|  1 | SIMPLE      | ebt   | ref    | PRIMARY,index_business_task_rid,index_business_task_bt | index_business_task_bt | 5       | const                 | 3341380 | Using where |
|  1 | SIMPLE      | bu    | eq_ref | PRIMARY,idx_buyer$user_country_id                      | PRIMARY                | 4       | cfec1.ebt.relative_id |       1 | Using where |
|  1 | SIMPLE      | ebtl  | ref    | index_business_tl_tid,index_business_tl_bt             | index_business_tl_tid  | 5       | cfec1.ebt.task_id     |       1 | Using where |
|  1 | SIMPLE      | ecs   | ref    | fk_strategy_bt                                         | fk_strategy_bt         | 4       | cfec1.bu.country_id   |       1 | Using where |
+----+-------------+-------+--------+--------------------------------------------------------+------------------------+---------+-----------------------+---------+-------------+

还是用原来的ebt作为驱动表(由此可看出MySQL优化器没有自动优化)
那么我的强制使用ebtl作为驱动表,改写sql如下,发现执行时间只有5s:
mysql>  SELECT      ebt.relative_type,        ebt.relative_Id,      bu.buyer_photo,      ebt.`business_type`,    bu.email,    bu.first_name,    bu.last_name     FROM      `edm$business_task_list` ebtl straight_join   `edm$business_task` ebt,     `buyer$user` bu,    `edm$country_strategy` ecs     WHERE ebt.task_id = ebtl.task_id    AND ebt.business_type = ebtl.business_type    AND bu.buyer_id = ebt.relative_id        AND ecs.country_id = bu.country_id     AND ebtl.business_type = 23        AND ebtl.exec_email = 0           AND ecs.delivery_time_point = '1:00'    AND TIMESTAMPDIFF(DAY,ebtl.create_time, '2015-09-14' ) = 0;
Empty set (4.99 sec)
查看执行计划,以ebtl作为了驱动表:
+----+-------------+-------+--------+--------------------------------------------------------+----------------------+---------+-----------------------+---------+-------------+
| id | select_type | table | type   | possible_keys                                          | key                  | key_len | ref                   | rows    | Extra       |
+----+-------------+-------+--------+--------------------------------------------------------+----------------------+---------+-----------------------+---------+-------------+
|  1 | SIMPLE      | ebtl  | ref    | index_business_tl_tid,index_business_tl_bt             | index_business_tl_bt | 10      | const,const           | 3312034 | Using where |
|  1 | SIMPLE      | ebt   | eq_ref | PRIMARY,index_business_task_rid,index_business_task_bt | PRIMARY              | 4       | cfec1.ebtl.task_id    |       1 | Using where |
|  1 | SIMPLE      | bu    | eq_ref | PRIMARY,idx_buyer$user_country_id                      | PRIMARY              | 4       | cfec1.ebt.relative_id |       1 | Using where |
|  1 | SIMPLE      | ecs   | ref    | fk_strategy_bt                                         | fk_strategy_bt       | 4       | cfec1.bu.country_id   |       1 | Using where |
+----+-------------+-------+--------+--------------------------------------------------------+----------------------+---------+-----------------------+---------+-------------+

至此该条语句的优化完成。
请使用浏览器的分享功能分享到微信等