mysql左连接顺序,如何理解正确的算法

gupuwyp2  于 2021-06-19  发布在  Mysql
关注(0)|答案(1)|浏览(410)

我真的很困惑,写左连接的正确顺序是什么,事实上,如果我把一个左连接从位置a移到z,查询速度会快3倍,但是为什么呢?为什么优化器不能自己获得正确的顺序?
如何理解用n个左连接编写查询的正确顺序?
例子:
慢速查询:

SELECT
    c.idRichiesta, i.idImmobile
FROM anagrafica AS cli
INNER JOIN richieste AS c  ON c.idCliente = cli.idCliente
INNER JOIN cat_richieste AS cr ON cr.idRichiesta = c.idRichiesta
LEFT JOIN (
    SELECT tmr.* FROM (
        (
            SELECT idRichiesta, id_comune, id_frazione, id_nazione
            FROM comuni_richieste
            WHERE idRichiesta = '129563'
        )
        UNION ALL
        (
            SELECT mr.idRichiesta, m.id_comune, m.id_frazione, m.id_nazione
            FROM macro_aree_richieste AS mr
            INNER JOIN macro_aree_dettaglio AS m ON m.id_macro=mr.id_macro
            WHERE mr.idRichiesta = '129563'
        )
    ) AS tmr
    GROUP BY tmr.idRichiesta, tmr.id_comune, tmr.id_frazione
) AS tcr ON tcr.idRichiesta = c.idRichiesta
LEFT JOIN richieste_coordinate_p AS tcrp ON tcrp.idRichiesta = c.idRichiesta
LEFT JOIN richieste_coordinate_c AS tcrc ON tcrc.idRichiesta = c.idRichiesta
INNER JOIN immobili i on i.idCategoria = cr.idCategoria
LEFT JOIN loc_geo as Ltg on Ltg.idImmobile = i.idImmobile
LEFT JOIN stato_mediazione AS s  ON s.id=i.stato_mediazione
WHERE
    i.proposta_in_corso!='2'
    AND (
        (
            (i.Motivazione = 'Vendita')
            AND (  i.Prezzo_Richiesto >= ( c.Prezzo_Min * (100 - 30)/100 ) )
            AND (( ( i.Prezzo_Richiesto * (100 - 30)/100 ) <= ( c.Prezzo_Max * (100 + 30)/100 ) ) or c.Prezzo_Max = 0 )
        )
        OR
        (
            (i.Motivazione ='Affitto/Vendita')
            AND (
                (( i.Prezzo_Richiesto2 >= ( c.Prezzo_Min  * (100 - 30)/100 )) AND ((( i.Prezzo_Richiesto2 * (100 - 30)/100 )  <= ( c.Prezzo_Max * (100 + 30)/100) ) or c.Prezzo_Max=0) AND c.Motivo_Richiesta ='Affitto')
                OR
                (( i.Prezzo_Richiesto >= ( c.Prezzo_Min  * (100 - 30)/100 )) AND ((( i.Prezzo_Richiesto * (100 - 30)/100 )  <= ( c.Prezzo_Max * (100 + 30)/100) ) or c.Prezzo_Max=0)  AND c.Motivo_Richiesta ='Acquisto')
            )
        )
    )
    AND (
        ( i.Citta = tcr.id_comune  AND ((i.ZonaCitta=tcr.id_frazione) OR (tcr.id_frazione = 0) ) )
        OR (
            Ltg.latitudine is not null and Ltg.longitudine is not null
            AND ( tcrp.poligono is not null AND
                ( ST_CONTAINS(tcrp.poligono, POINT(Ltg.latitudine, Ltg.longitudine)) )
                OR ( tcrc.centro is not null AND
                    round (((acos( sin(( X(tcrc.centro) * 0.0174532925)) * sin((Ltg.latitudine * 0.0174532925)) + cos(( X(tcrc.centro) * 0.0174532925)) * cos((Ltg.latitudine * 0.0174532925)) * cos((( Y(tcrc.centro) - Ltg.longitudine) * 0.0174532925)))) * 57.2957795131) * 111.18957696, 2) <= (tcrc.raggio / 1000)
                )
            )
        )
    )
    AND i.Citta>0
    AND (c.idRichiesta = '129563')
    AND (s.id IS NULL OR s.vendibile='si')

GROUP BY i.idImmobile

解释

+------+--------------+------------------+--------+-------------------------------------------------------+-------------+---------+---------------------------------------+------+---------------------------------+--+
|  id  | select_type  |      table       |  type  |                     possible_keys                     |     key     | key_len |                  ref                  | rows |              Extra              |  |
+------+--------------+------------------+--------+-------------------------------------------------------+-------------+---------+---------------------------------------+------+---------------------------------+--+
| 1    | PRIMARY      | tcrp             | system | idRichiesta                                           | NULL        | NULL    | NULL                                  | 0    | const row not found             |  |
| 1    | PRIMARY      | tcrc             | system | idRichiesta                                           | NULL        | NULL    | NULL                                  | 0    | const row not found             |  |
| 1    | PRIMARY      | c                | const  | PRIMARY,idCliente,Prezzo_Max,Motivo_Richiesta         | PRIMARY     | 4       | const                                 | 1    | Using temporary; Using filesort |  |
| 1    | PRIMARY      | cli              | const  | PRIMARY                                               | PRIMARY     | 4       | const                                 | 1    | Using index                     |  |
| 1    | PRIMARY      | <derived2>       | ref    | <auto_key1>                                           | <auto_key1> | 4       | const                                 | 0    | Using where                     |  |
| 1    | PRIMARY      | cr               | ref    | idRichiesta,idCategoria                               | idRichiesta | 4       | const                                 | 9    | Using index condition           |  |
| 1    | PRIMARY      | i                | ref    | PRIMARY,idProprietario,id_cantiere,codice_agenzia,... | idCategoria | 5       | test_import2.cr.idCategoria     | 2780 | Using where                     |  |
| 1    | PRIMARY      | Ltg              | ref    | idImmobile                                            | idImmobile  | 4       | test_import2.i.idImmobile       | 1    | Using where                     |  |
| 1    | PRIMARY      | s                | eq_ref | PRIMARY                                               | PRIMARY     | 4       | test_import2.i.stato_mediazione | 1    | Using where                     |  |
| 2    | DERIVED      | <derived3>       | ALL    | NULL                                                  | NULL        | NULL    | NULL                                  | 9    | Using temporary; Using filesort |  |
| 3    | DERIVED      | comuni_richieste | ref    | idRichiesta                                           | idRichiesta | 4       | const                                 | 7    | NULL                            |  |
| 4    | UNION        | mr               | ref    | idRichiesta,id_macro                                  | idRichiesta | 4       | const                                 | 1    | NULL                            |  |
| 4    | UNION        | m                | ref    | id_macro                                              | id_macro    | 4       | test_import2.mr.id_macro        | 1    | NULL                            |  |
| NULL | UNION RESULT | <union3,4>       | ALL    | NULL                                                  | NULL        | NULL    | NULL                                  | NULL | Using temporary                 |  |
+------+--------------+------------------+--------+-------------------------------------------------------+-------------+---------+---------------------------------------+------+---------------------------------+--+

快速查询:

SELECT
    c.idRichiesta, i.idImmobile
FROM anagrafica AS cli
INNER JOIN richieste AS c  ON c.idCliente = cli.idCliente
INNER JOIN cat_richieste AS cr ON cr.idRichiesta = c.idRichiesta

LEFT JOIN richieste_coordinate_p AS tcrp ON tcrp.idRichiesta = c.idRichiesta
LEFT JOIN richieste_coordinate_c AS tcrc ON tcrc.idRichiesta = c.idRichiesta
INNER JOIN immobili i on i.idCategoria = cr.idCategoria
LEFT JOIN loc_geo as Ltg on Ltg.idImmobile = i.idImmobile
LEFT JOIN stato_mediazione AS s  ON s.id=i.stato_mediazione
LEFT JOIN (
    SELECT tmr.* FROM (
        (
            SELECT idRichiesta, id_comune, id_frazione, id_nazione
            FROM comuni_richieste
            WHERE idRichiesta = '129563'
        )
        UNION ALL
        (
            SELECT mr.idRichiesta, m.id_comune, m.id_frazione, m.id_nazione
            FROM macro_aree_richieste AS mr
            INNER JOIN macro_aree_dettaglio AS m ON m.id_macro=mr.id_macro
            WHERE mr.idRichiesta = '129563'
        )
    ) AS tmr
    GROUP BY tmr.idRichiesta, tmr.id_comune, tmr.id_frazione
) AS tcr ON tcr.idRichiesta = c.idRichiesta
WHERE
    i.proposta_in_corso!='2'
    AND (
        (
            (i.Motivazione = 'Vendita')
            AND (  i.Prezzo_Richiesto >= ( c.Prezzo_Min * (100 - 30)/100 ) )
            AND (( ( i.Prezzo_Richiesto * (100 - 30)/100 ) <= ( c.Prezzo_Max * (100 + 30)/100 ) ) or c.Prezzo_Max = 0 )
        )
        OR
        (
            (i.Motivazione ='Affitto/Vendita')
            AND (
                (( i.Prezzo_Richiesto2 >= ( c.Prezzo_Min  * (100 - 30)/100 )) AND ((( i.Prezzo_Richiesto2 * (100 - 30)/100 )  <= ( c.Prezzo_Max * (100 + 30)/100) ) or c.Prezzo_Max=0) AND c.Motivo_Richiesta ='Affitto')
                OR
                (( i.Prezzo_Richiesto >= ( c.Prezzo_Min  * (100 - 30)/100 )) AND ((( i.Prezzo_Richiesto * (100 - 30)/100 )  <= ( c.Prezzo_Max * (100 + 30)/100) ) or c.Prezzo_Max=0)  AND c.Motivo_Richiesta ='Acquisto')
            )
        )
    )
    AND (
        ( i.Citta = tcr.id_comune  AND ((i.ZonaCitta=tcr.id_frazione) OR (tcr.id_frazione = 0) ) )
        OR (
            Ltg.latitudine is not null and Ltg.longitudine is not null
            AND ( tcrp.poligono is not null AND
                ( ST_CONTAINS(tcrp.poligono, POINT(Ltg.latitudine, Ltg.longitudine)) )
                OR ( tcrc.centro is not null AND
                    round (((acos( sin(( X(tcrc.centro) * 0.0174532925)) * sin((Ltg.latitudine * 0.0174532925)) + cos(( X(tcrc.centro) * 0.0174532925)) * cos((Ltg.latitudine * 0.0174532925)) * cos((( Y(tcrc.centro) - Ltg.longitudine) * 0.0174532925)))) * 57.2957795131) * 111.18957696, 2) <= (tcrc.raggio / 1000)
                )
            )
        )
    )
    AND i.Citta>0
    AND (c.idRichiesta = '129563')
    AND (s.id IS NULL OR s.vendibile='si')

GROUP BY i.idImmobile

解释

+------+--------------+------------------+--------+-------------------------------------------------------+-------------+---------+---------------------------------------+------+---------------------------------+--+
|  id  | select_type  |      table       |  type  |                     possible_keys                     |     key     | key_len |                  ref                  | rows |              Extra              |  |
+------+--------------+------------------+--------+-------------------------------------------------------+-------------+---------+---------------------------------------+------+---------------------------------+--+
| 1    | PRIMARY      | tcrp             | system | idRichiesta                                           | NULL        | NULL    | NULL                                  | 0    | const row not found             |  |
| 1    | PRIMARY      | tcrc             | system | idRichiesta                                           | NULL        | NULL    | NULL                                  | 0    | const row not found             |  |
| 1    | PRIMARY      | c                | const  | PRIMARY,idCliente,Prezzo_Max,Motivo_Richiesta         | PRIMARY     | 4       | const                                 | 1    | Using temporary; Using filesort |  |
| 1    | PRIMARY      | cli              | const  | PRIMARY                                               | PRIMARY     | 4       | const                                 | 1    | Using index                     |  |
| 1    | PRIMARY      | cr               | ref    | idRichiesta,idCategoria                               | idRichiesta | 4       | const                                 | 9    | Using index condition           |  |
| 1    | PRIMARY      | i                | ref    | PRIMARY,idProprietario,id_cantiere,codice_agenzia,... | idCategoria | 5       | test_import2.cr.idCategoria     | 2780 | Using where                     |  |
| 1    | PRIMARY      | Ltg              | ref    | idImmobile                                            | idImmobile  | 4       | test_import2.i.idImmobile       | 1    | NULL                            |  |
| 1    | PRIMARY      | s                | eq_ref | PRIMARY                                               | PRIMARY     | 4       | test_import2.i.stato_mediazione | 1    | Using where                     |  |
| 1    | PRIMARY      | <derived2>       | ref    | <auto_key1>                                           | <auto_key1> | 4       | test_import2.cr.idRichiesta     | 0    | Using where                     |  |
| 2    | DERIVED      | <derived3>       | ALL    | NULL                                                  | NULL        | NULL    | NULL                                  | 9    | Using temporary; Using filesort |  |
| 3    | DERIVED      | comuni_richieste | ref    | idRichiesta                                           | idRichiesta | 4       | const                                 | 7    | NULL                            |  |
| 4    | UNION        | mr               | ref    | idRichiesta,id_macro                                  | idRichiesta | 4       | const                                 | 1    | NULL                            |  |
| 4    | UNION        | m                | ref    | id_macro                                              | id_macro    | 4       | test_import2.mr.id_macro        | 1    | NULL                            |  |
| NULL | UNION RESULT | <union3,4>       | ALL    | NULL                                                  | NULL        | NULL    | NULL                                  | NULL | Using temporary                 |  |
+------+--------------+------------------+--------+-------------------------------------------------------+-------------+---------+---------------------------------------+------+---------------------------------+--+

正如您所看到的,唯一的区别是派生查询的左连接的位置。但是为什么第二个比第一个快呢?如何在解释输出中看到这一点?
随时问我你需要什么(索引列表,创建表等)。谢谢大家。

gywdnpxw

gywdnpxw1#

你用的是什么版本?较新的版本将具体化派生表,并为它们发现一个合适的索引,如 <auto_key1> . 这有时是一种性能优势。旧版本将简单地重新执行 SELECT (和 UNION ,在您的情况下)每次它到达 LEFT JOIN .
不要使用 LEFT 除非你需要。以后一定要买 LEFT 即使缺少行(else下降 LEFT .) ORs 优化不好。看看你能不能摆脱他们。

相关问题