以下查询突然变得极其缓慢(似乎根本没有完成),表a中的行超过 25.000 行(尝试向查询添加限制x):
select a.*, b.column
from table_a a
left join table_b b
on (a.message_id = b.message_id)
where date_sub(curdate(), interval 30 day) < a.date
and (
b.message_id is NULL or
(
b.message_id is not NULL
and a.message_id = b.message_id
and b.redeemed > 0
)
)
order by a.id DESC
a.message_id
和b.message_id
都有一个索引。 table_a将包含比table_b
据我所知,左连接与组合为NULL 会导致mysql服务器达到极限,但我不知道如何重写查询以避免左连接。
基本上我想查询表a并检查表b中是否有匹配的条目。如果是这种情况,我想将表b中的日期合并到结果中。
非常感谢任何帮助!
答案 0 :(得分:1)
首先,我将最后一个条件简化为
AND ( b.message_id IS NULL OR b.redeemed > 0 )
现在您的查询具有以下基本结构:
a LEFT JOIN b
WHERE b IS NULL
OR b.x > 0 /* MySQL may or may not be able to optimize LEFT JOIN + OR*/
我改写为UNION:
a LEFT JOIN b
WHERE b IS NULL
UNION ALL
a INNER JOIN b /* LEFT -> INNER */
WHERE b.x > 0
所以这是你的复杂查询:
( SELECT
a.*,
NULL AS column /* help MySQL a bit :) */
FROM table_a a
LEFT JOIN table_b b ON a.message_id = b.message_id
WHERE DATE_SUB(CURDATE(), INTERVAL 30 DAY) < a.date
AND b.message_id IS NULL
) UNION ALL (
SELECT
a.*,
b.column
FROM table_a a
INNER JOIN table_b b ON a.message_id = b.message_id
WHERE DATE_SUB(CURDATE(), INTERVAL 30 DAY) < a.date
AND b.redeemed > 0
)
ORDER BY a.id DESC
您可以使用LEFT JOIN更改第一个子选择以使用NOT EXISTS,但我不知道它是否有帮助:
SELECT
a.*,
NULL AS column /* b's column(s) -> aliased NULL*/
FROM table_a a
WHERE DATE_SUB(CURDATE(), INTERVAL 30 DAY) < a.date
AND NOT EXISTS (
SELECT 1
FROM b
WHERE a.message_id = b.message_id
)