我的查询如下:
SELECT DISTINCT O.MessageID, OD.Destination
FROM OutboundMessages AS O LEFT JOIN
OutboundMessagesDetails AS OD
ON OD.MessageID=O.MessageID
WHERE O.UserID = 18097 AND
O.Status IS NOT NULL AND
O.Status <> 'Deleted'
ORDER BY O.ScheduleDate DESC
LIMIT 0, 25
完成需要大约50秒。这是解释:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE O NULL index PRIMARY,UserSchedule UserSchedule 4 NULL 15055 0.08 Using where; Using temporary
1 SIMPLE OD NULL eq_ref PRIMARY PRIMARY 8 NMV2_Messaging.O.MessageID 1 100.00 Using index; Distinct
请注意,ORDER BY
子句位于第一个表中的字段(OutboundMessages AS O
)
如果我删除ORDER BY
或LEFT JOIN
,则需要0.00035秒才能完成。
为什么这么慢?大概是因为MySQL在LEFT JOINing
之前的每一行都是ORDER BY
。如果这是正确的,有没有办法可以阻止这种情况并让MySQL在过滤,限制和排序后执行LEFT JOIN
?
答案 0 :(得分:1)
为了实际只读取25行(请参阅LIMIT 25
),INDEX
需要超过ORDER BY
。
要让INDEX
超过ORDER BY
,索引需要以ORDER BY
(ScheduleDate
中的列结束,在您的情况下;还有其他条件,但他们相遇)。 和您需要完全了解WHERE
子句。
要通过WHERE
子句完全 所有,AND'd
条款必须为column = constant
。 <>
不会做。 IS NOT NULL
不会做。范围(在您的情况下不存在)不会,除非与ORDER BY
相同。
所以,这是不可能的。
无论如何,DISTINCT
(或GROUP BY
)表示在计算25行之前必须进行重复数据删除。
但真的需要DISTINCT
吗?那么,对于给定的Destination
,是否可以存在相同 MessageID
的多个副本?如果没有,DISTINCT
会为你做什么吗?
为什么LEFT
?这意味着Destination
是可选的。
这是另一种表述;它可能会或可能不会更好:
SELECT O.MessageID,
( SELECT Destination
FROM OutboundMessagesDetails
WHERE MessiageID = O.MessageID
) AS Destination
FROM OutboundMessages AS O
WHERE O.UserID = 18097
AND O.Status IS NOT NULL
AND O.Status <> 'Deleted'
ORDER BY O.ScheduleDate DESC
LIMIT 0, 25
注意:内部SELECT
可能需要DISTINCT
。
你需要
INDEX(UserID, -- first
ScheduleDate, -- second
Status, MessageID) -- (either order) to make it "covering"
哦,Status
有什么可能的值?如果只有另一个选择,则将两个子句替换为AND O.Status = 'Valid'
。现在你可以用它来一直通过!
INDEX(UserID, Status, ScheduleDate, MessageID)
请注意,这与我之前的建议不同。
注意:NULL
不等于任何内容,甚至不等于NULL
。
而且,是的,另一个表需要INDEX(MessageID, Destination)
(除非它有PRIMARY KEY(MesssageID)
并且是InnoDB)。
答案 1 :(得分:0)
对于此查询:
SELECT DISTINCT O.MessageID, OD.Destination
FROM OutboundMessages O LEFT JOIN
OutboundMessagesDetails OD
ON OD.MessageID = O.MessageID
WHERE O.UserID = 18097 AND
O.Status IS NOT NULL AND
O.Status <> 'Deleted'
ORDER BY O.ScheduleDate DESC
LIMIT 0, 25;
您需要OutboundMessages(UserID, Status, MessageId, Scheduledate)
和OutboundMessagesDetails(MessageID, Destination)
上的索引。
SELECT DISTINCT
也会降低查询速度。如果不需要,请将其删除。
我想要注意的是,您的查询类型没有意义,因为您有SELECT DISTINCT
,然后查询按不在SELECT
中的列排序。大多数数据库会拒绝这一点MySQL允许它。在这种特殊情况下,这是合理的,因为DISTINCT
(可能)是同一个表中的主键。