繁体   English   中英

MySQL性能差

[英]MySQL Distinct Poor performance

我有一个带有多个左连接的Distinct Select语句,当我的where子句很大时,该语句的性能很差。 以下是我的声明

SELECT  DISTINCT u.*, ri.id as reg_id, d.id as dist_id
    FROM  users u
    LEFT JOIN  earned_points ep ON u.id = ep.user_id
    LEFT JOIN  distributors d ON d.id = ep.distributor_id
      OR  d.id = u.distributor_id
      OR  d.id = u.additional_distributor_id
    LEFT JOIN  registration_items_users riu ON u.id = riu.user_id
      AND  riu.distributor_id = d.id
      AND  riu.registration_item_id = 21
    LEFT JOIN  registration_items ri ON riu.registration_item_id = ri.id
    WHERE  d.id IN (201,281,321,631,901,971,1211,1601,1611,1621,
               1631,1641,1651,1661,1671,1681,1691,1701,1711,1721,1731,
               1741,1751,1761,1771,1781,2281,2291,2401,2781,2801,2931 );

该查询的解释如下: select_explain

此查询大约需要4秒钟才能完成。 如果我将where减少到一个id,那么它最多可以加速170ms。

将不胜感激有关如何使此查询更快的任何建议。

谢谢

编辑

我能够根据Rick James(接受的答案)的建议提出一个解决方案。 使用Union并摆脱Left Joins and Distinct可以达到目的。 与上面的4秒版本相比,此新查询大约需要200毫秒。

(SELECT  u.*, 
   (SELECT riu.registration_item_id 
       FROM registration_items_users riu 
       WHERE riu.user_id = u.id 
           AND riu.distributor_id = d.id 
           AND riu.registration_item_id = 21) as reg_id,
   d.id as dist_id
   FROM users u
   JOIN earned_points ep ON u.id = ep.user_id
   JOIN distributors d ON d.id = ep.distributor_id
       WHERE d.id IN (201,281,321,631,901,971,1211,1601,1611,1621,
            1631,1641,1651,1661,1671,1681,1691,1701,1711,1721,1731,
            1741,1751,1761,1771,1781,2281,2291,2401,2781,2801,2931))
   UNION
(SELECT  u.*, 
   (SELECT riu.registration_item_id 
       FROM registration_items_users riu 
       WHERE riu.user_id = u.id 
           AND riu.distributor_id = d.id 
           AND riu.registration_item_id = 21) as reg_id,
   d.id as dist_id
   FROM users u
   JOIN distributors d ON d.id = u.distributor_id
       WHERE d.id IN (201,281,321,631,901,971,1211,1601,1611,1621,
            1631,1641,1651,1661,1671,1681,1691,1701,1711,1721,1731,
            1741,1751,1761,1771,1781,2281,2291,2401,2781,2801,2931))
   UNION
(SELECT  u.*, 
   (SELECT riu.registration_item_id 
       FROM registration_items_users riu 
       WHERE riu.user_id = u.id 
           AND riu.distributor_id = d.id 
           AND riu.registration_item_id = 21) as reg_id,
   d.id as dist_id
   FROM users u
   JOIN distributors d ON d.id = u.additional_distributor_id
       WHERE d.id IN (201,281,321,631,901,971,1211,1601,1611,1621,
            1631,1641,1651,1661,1671,1681,1691,1701,1711,1721,1731,
            1741,1751,1761,1771,1781,2281,2291,2401,2781,2801,2931))

EXPLAIN ,查看u行。 它正在执行大约6974行的“表扫描”。

除非“ right”表是可选的,否则请摆脱LEFT

OR变成UNION ; 那就是索引使您失败的地方。 UNION ALLUNION DISTINCT快;请选择任何一个有意义的。)

假设可以删除LEFTs ,并且可以将DISTINCTSELECT移到UNION

SELECT  u.*, ri.id as reg_id, d.id as dist_id
    FROM  users u
    JOIN  earned_points ep ON u.id = ep.user_id  -- ep needed only for this
    JOIN  distributors d ON d.id = ep.distributor_id  -- This one line differs
    JOIN  registration_items_users riu ON u.id = riu.user_id
      AND  riu.distributor_id = d.id
      AND  riu.registration_item_id = 21
    JOIN  registration_items ri ON riu.registration_item_id = ri.id
    WHERE  d.id IN (201,281,321,631,901,971,1211,1601,1611,1621,
                1631,1641,1651,1661,1671,1681,1691,1701,1711,1721,1731,
                1741,1751,1761,1771,1781,2281,2291,2401,2781,2801,2931 
                   )
    UNION  DISTINCT 
SELECT  u.*, ri.id as reg_id, d.id as dist_id
    FROM  users u
    JOIN  distributors d ON d.id = u.distributor_id
    JOIN  registration_items_users riu ON u.id = riu.user_id
      AND  riu.distributor_id = d.id
      AND  riu.registration_item_id = 21
    JOIN  registration_items ri ON riu.registration_item_id = ri.id
    WHERE  d.id IN (201,281,321,631,901,971,1211,1601,1611,1621,
                1631,1641,1651,1661,1671,1681,1691,1701,1711,1721,1731,
                1741,1751,1761,1771,1781,2281,2291,2401,2781,2801,2931 
                   )
    UNION  DISTINCT 
SELECT  u.*, ri.id as reg_id, d.id as dist_id
    FROM  users u
    JOIN  distributors d ON d.id = u.additional_distributor_id
    JOIN  registration_items_users riu ON u.id = riu.user_id
      AND  riu.distributor_id = d.id
      AND  riu.registration_item_id = 21
    JOIN  registration_items ri ON riu.registration_item_id = ri.id
    WHERE  d.id IN (201,281,321,631,901,971,1211,1601,1611,1621,
                1631,1641,1651,1661,1671,1681,1691,1701,1711,1721,1731,
                1741,1751,1761,1771,1781,2281,2291,2401,2781,2801,2931 
                   ) ;

跨列展开数组通常是一个坏主意。 这似乎是distributors正在发生的事情。 这种混乱可能是这种情况的结果。

编辑

更好的是将rirui内容从选择中拉出,并将其转换为子查询。 这是要点; 我没有精力写这一切:

SELECT x.*,
        ( SELECT ... ri and rui stuff ... ) AS reg_id
    FROM (
        --  from above, less the ri and rui stuff:
        SELECT ...
        UNION DISTINCT
        SELECT ...
        UNION DISTINCT
        SELECT ...
         ) AS x;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM