LEFT JOIN的位置如何影响查询和优化器?

时间:2017-04-23 18:40:24

标签: mysql performance left-join query-optimization

当我发现两个不同的查询时,我看到一个奇怪的Mysql行为,其中一个小差异,一个左连接的位置。

慢查询:

SELECT i.id_affiliate, i.id_franchising, i.Codice
FROM network_configuration_affiliate AS c
INNER JOIN franchising AS fr ON fr.id = c.id_franchising
INNER JOIN network_selected_car AS i ON c.id_affiliate = i.id_affiliate
INNER JOIN (
  select T1.id_car, T1.id_network, T1.id_franchising, T1.id_agencie
  from network_car_destinations as T1
  where T1.id_network='12' and ( T1.id_franchising = 968 or T1.id_franchising = 974 )
) AS n ON n.id_franchising=i.id_franchising AND n.id_car=i.id_car AND c.id_network=n.id_network
INNER JOIN affiliate_tipologies AS t ON t.id_tipology_ag=i.idCategory AND t.id_franchising=i.id_franchising
INNER JOIN network_assoc_tipologies AS p ON p.id_network=c.id_network AND p.id_default=t.id_tipology_net
LEFT JOIN  network_conf_users as ce on ce.id_affiliate = i.id_affiliate and ce.id_user = i.id_user
WHERE c.id_network='12' and c.code_affiliate='69842' AND c.configured = 'yes' AND i.Code_car not like '' and p.code != '0'
GROUP BY i.Code_car

快速:

select T2.* from (
  SELECT i.`id_affiliate`, i.id_franchising, i.Code_car, i.id_user
  FROM network_configuration_affiliate  AS c
  INNER JOIN franchising AS fr ON fr.id = c.id_franchising
  INNER JOIN network_selected_car  AS i ON c.`id_affiliate` = i.`id_affiliate`
  INNER JOIN (
    select T1.id_car, T1.id_network, T1.id_franchising, T1.id_agencie
    from network_car_destinations  as T1
    where T1.id_network='12' and ( T1.id_franchising = 968 or T1.id_franchising = 974 )
  ) AS n ON n.id_franchising=i.id_franchising AND n.id_car=i.id_car AND c.id_network=n.id_network
  INNER JOIN affiliate_tipologies  AS t ON t.id_tipology_ag=i.idCategory AND t.id_franchising=i.id_franchising
  INNER JOIN network_assoc_tipologies AS p ON p.id_network=c.id_network AND p.id_default=t.id_tipology_net

  WHERE c.id_network='12' and c.code_affiliate='69842' AND c.configured = 'yes' AND i.Code_car not like ''
  GROUP BY i.Code_car
) as T2
LEFT JOIN  network_conf_users as ce on ce.`id_affiliate` =  T2.`id_affiliate` and ce.id_user = T2.id_user

WHERE c.id_network='12' and c.code_affiliate='69842' AND c.configured = 'yes' AND i.Code_car not like '' and p.code != '0'
GROUP BY i.Code_car

EXPLAIN几乎相同,两个查询的结果相同,但第一个查询结束时间为20秒,第二个查询结果为0.02,左连接的位置如何影响查询的执行?

EXPLAIN - 慢查询:

id  select_type     table       type        possible_keys                                       key                         key_len ref                 rows    filtered    Extra
1   PRIMARY         c           index_merge id_affiliate,id_network,configured,code_affiliate   code_affiliate,id_network   203,5   NULL                1       100.00  Using intersect(code_affiliate,id_network); Using where; Using temporary; Using filesort
1   PRIMARY         fr          eq_ref      PRIMARY                                             PRIMARY                     4       c.id_franchising    1       100.00  Using index
1   PRIMARY         <derived2>  ref         <auto_key1>                                         <auto_key1>                 5       const               10      100.00  Using where
1   PRIMARY         t           ref         id_franchising,id_tipology_ag,id_tipology_net       id_franchising              5       n.id_franchising    13      100.00  Using where
1   PRIMARY         p           ref         id_network,id_default                               id_default                  5       t.id_tipology       26      100.00  Using where
1   PRIMARY         i           ref         id_car,id_affiliate,id_franchising,idCategory       id_car                      5       n.id_car            3       100.00  Using where
1   PRIMARY         ce          ALL         id_affiliate,id_user                                NULL                        NULL    NULL                4       75.00   Using where; Using join buffer (Block Nested Loop)
2   DERIVED         T1          ref         id_franchising,id_network                           id_network                  5       const           136952      100.00  Using where

显示警告:

Level   Code    Message
Note    1003    /* select#1 */
select  `i`.`id_affiliate` AS `id_affiliate`,
        `i`.`id_franchising` AS `id_franchising`,
        `i`.`Code_car` AS `Code_car`
    from  `network_configuration_affiliate` `c`
    join  `franchising` `fr`
    join  `network_selected_car` `i`
    join  (/* select#2 */ 
        select  `T1`.`id_car` AS `id_car`,
                `T1`.`id_network` AS `id_network`,
                `T1`.`id_franchising` AS `id_franchising`,
                `T1`.`id_agencie` AS `id_agencie`
            from  `network_car_destinations` `T1`
            where  ((`T1`.`id_network` = '12')
                      and  ((`T1`.`id_franchising` = 968)
                              or  (`T1`.`id_franchising` = 974)))
          ) `n`
    join  `affiliate_tipologies` `t`
    join  `network_assoc_tipologies` `p`
    left join  `network_conf_users` `ce` on(((`ce`.`id_user` = `i`.`id_user`)
                      and  (`ce`.`id_affiliate` = `c`.`id_affiliate`))
                          )
    where  ((`fr`.`id` = `c`.`id_franchising`)
              and  (`i`.`id_affiliate` = `c`.`id_affiliate`)
              and  (`i`.`id_car` = `n`.`id_car`)
              and  (`t`.`id_franchising` = `n`.`id_franchising`)
              and  (`i`.`id_franchising` = `n`.`id_franchising`)
              and  (`i`.`idCategory` = `t`.`id_tipology_ag`)
              and  (`p`.`id_default` = `t`.`id_tipology_net`)
              and  (`n`.`id_network` = `c`.`id_network`)
              and  (`p`.`id_network` = `c`.`id_network`)
              and  (`c`.`configured` = 'yes')
              and  (`c`.`code_affiliate` = '69842')
              and  (`c`.`id_network` = '12')
              and  (not((`i`.`Code` like '')))
              and  (`p`.`code` <> '0')
           )
    group by  `i`.`Code_car`

快速查询:

id  select_type     table       type            possible_keys                                                   key                                     key_len     ref                 rows    filtered    Extra
1   PRIMARY         <derived2>  ALL             NULL                                                            NULL                                    NULL        NULL                7280    100.00      NULL
1   PRIMARY         ce          ALL             id_affiliate,id_user                                            NULL                                    NULL        NULL                4       75.00       Using where; Using join buffer (Block Nested Loop)
2   DERIVED         c           index_merge     id_affiliate,id_network,configured,code_affiliate               code_affiliate,id_network               203,5       NULL                1       100.00      Using intersect(codice_affiliato,id_network); Using where; Using temporary; Using filesort
2   DERIVED         fr          eq_ref          PRIMARY                                                         PRIMARY                                 4           c.id_franchising    1         100.00    Using index
2   DERIVED         <derived3>  ref             <auto_key1>                                                     <auto_key1>                             5           const               10      100.00      Using where
2   DERIVED         i           ref             id_car,id_affiliate,id_franchising,idCategory                   id_car                                  5           n.id_car            2       100.00      Using where
2   DERIVED         t           ref             id_franchising,id_tipology_ag,id_tipology_net                   id_franchising                          5           n.id_franchising    14      100.00      Using where
2   DERIVED         p           ref             id_network,id_default                                           id_default                              5           t.id_tipology_net   26      100.00      Using where
3   DERIVED         T1          ref             id_franchising,id_network                                       id_network                              5           const               133324  100.00      Using where

显示警告:

Level   Code    Message
Note    1003    /* select#1 */
select  `T2`.id_affiliate AS id_affiliate,
        `T2`.`id_franchising` AS `id_franchising`,
        `T2`.Code_car AS Code_car,`T2`.id_user AS id_user
    from  (/* select#2 */ 
        select  `i`.id_affiliate AS id_affiliate,
                `i`.`id_franchising` AS `id_franchising`,
                `i`.Code_car AS Code_car,`i`.id_user AS id_user
            from  network_configuration_affiliate `c`
            join  `franchising` `fr`
            join  network_selected_car `i`
            join  (/* select#3 */ 
                select  `T1`.id_car AS id_car,
                        `T1`.`id_network` AS `id_network`,
                        `T1`.`id_franchising` AS `id_franchising`,
                        `T1`.`id_agencie` AS `id_agencie`
                    from  network_car_destinations `T1`
                    where  ((`T1`.`id_network` = '12')
                              and  ((`T1`.`id_franchising` = 968)
                                      or  (`T1`.`id_franchising` = 974)))
                  ) `n`
            join  affiliate_tipologies `t`
            join  network_assoc_tipologies `p`
            where  ((`fr`.`id` = `c`.`id_franchising`)
                      and  (`i`.id_affiliate = `c`.id_affiliate)
                      and  (`i`.id_car = `n`.id_car)
                      and  (`i`.`id_franchising` = `n`.`id_franchising`)
                      and  (`t`.`id_franchising` = `n`.`id_franchising`)
                      and  (`t`.`id_tipology_ag` = `i`.`idCategory`)
                      and  (`p`.`id_default` = `t`.`id_tipology_net`)
                      and  (`n`.`id_network` = `c`.`id_network`)
                      and  (`p`.`id_network` = `c`.`id_network`)
                      and  (`c`.`configured` = 'yes')
                      and  (`c`.`code_affiliate` = '69842')
                      and  (`c`.`id_network` = '12')
                      and  (not((`i`.Code_car like '')))
                   )
            group by  `i`.Code_car
          ) `T2`
    left join  network_conf_users `ce` on(((`ce`.id_affiliate = `T2`.id_affiliate)
                      and  (`ce`.id_user = `T2`.id_user))
                          )
    where  1 

2 个答案:

答案 0 :(得分:0)

左连接找到左边的那些字段并从右边找到那些字段,而内部连接将查找所有字段。通过不需要组织额外的列来保持简单,查询完成得更快。

答案 1 :(得分:0)

请告诉我们EXPLAINs

如果优化程序确定它没有任何区别,则会将LEFT JOIN变为JOIN。请EXPLAIN EXTENDED SELECT ...然后立即SHOW WARNINGS;,以便我们查看是否发生了这种情况。

优化工具会尝试JOINing的各种订单(在没有LEFTRIGHT的情况下)。因此,如果LEFT真的是多余的,我希望EXPLAINs能够使表格具有相同的顺序。

通常情况下,优化工具会以示例中的“派生”表n开头。但它可能隐藏在LEFT

之后

你有“复合”索引吗?这些可能是有益的:

T1:  INDEX(id_network, id_franchising) -- in this order
c:   INDEX(id_network, code_affiliate, configured)

<强>修订

随着查询的最近更改,我看到了这种模式:

慢速:

SELECT ...
    FROM ...
    JOIN ...
    GROUP BY ...

快速:

SELECT ...
    FROM ( SELECT ...
        FROM ...
        GROUP BY ... )
    JOIN ...

LEFT对问题只是部分重要;任何JOIN都可能出现此问题。)

我称之为慢速“膨胀 - 放气”。我的意思是,首先它确实加入了连接,从而增加了行数。然后它做了一个GROUP BY,它将结果缩小了。

在进行最终加入之前,快速放气,导致整体效果降低。

通过使用“复合”索引,几乎总能改进

index merge intersect。在这种情况下,我建议使用c。 (这会加速查询的两个版本。)