我有一个包含多个左连接的 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 );
此查询大约需要 4 秒才能完成。如果我将 where 减少到一个 id,那么它会加速到大约 170 毫秒。
如有任何关于如何加快查询速度的建议,我们将不胜感激。
谢谢
编辑
我能够根据 Rick James(接受的答案)的建议提出解决方案。使用 Union 并摆脱 Left Joins 和 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 行的“表扫描”。
去掉 LEFT
除非“右”表是可选的。
将OR
转换为UNION
;那就是索引让您失望的地方。 (UNION ALL
比 UNION DISTINCT
更快;选择一个有意义的。)
假设 LEFTs
可以被删除,并且 DISTINCT
可以从 SELECT
移动到 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
正在发生的事情。而这个烂摊子可能就是这样的结果。
编辑
更好的方法是将 ri
和 rui
内容从选择中拉出并将其转换为子查询。这是要点;我没有精力把它全部写完:
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;
关于MySQL Distinct 性能不佳,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35560850/