我有一个聊天消息表,已经增长到> 4m行。
我需要在特定日期范围内向用户发送消息。
起初这个查询还可以,但是当前表的大小太长了(> 10秒)。
我尝试创建了许多索引组合; MySQL在messageType + sentDate
上使用复合索引SELECT `ofMessageArchive`.*
FROM `ofMessageArchive`
WHERE `ofMessageArchive`.`messageType` IN ('Message')
AND (ofMessageArchive.fromJID = 'user@example.com' OR ofMessageArchive.toJID = 'user@example.com')
AND (ofMessageArchive.sentDate > '1462235333109')
ORDER BY ofMessageArchive.sentDate ASC LIMIT 50
我可以如何优化此查询?
[编辑] EXPLAIN
结果:
+----+-------------+------------------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------+---------+-------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------+---------+-------+--------+-------------+
| 1 | SIMPLE | ofMessageArchive | ref | index_ofMessageArchive_on_fromJID_and_toJID,index_ofMessageArchive_on_sentDate,index_ofMessageArchive_on_messageType,idxMessageTypeSentDate,ofMessageArchive_fromjid_idx,ofMessageArchive_tojid_idx | idxMessageTypeSentDate | 767 | const | 731570 | Using where |
+----+-------------+------------------+------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------+---------+-------+--------+-------------+
答案 0 :(得分:0)
您遇到了对传入邮件的处理方式与传入邮件不同(基本上是规范化问题)的问题,因此您无法直接在用户名上使用索引,这可能是您最重要的值。
如果还没有,请创建索引ofMessageArchive(fromJID, messageType, sentDate)
和
ofMessageArchive(toJID, messageType, sentDate)
(可能以不同的顺序排列,具体取决于您对这些列中的每个列有多少不同的值以及您使用的其他查询,但是从此顺序开始)。
要使用这些索引,请使用union
:
select * from
( (SELECT `ofMessageArchive`.*
FROM `ofMessageArchive`
WHERE (ofMessageArchive.fromJID = 'user@example.com')
AND `ofMessageArchive`.`messageType` IN ('Message')
AND (ofMessageArchive.sentDate > '1462235333109')
ORDER BY ofMessageArchive.sentDate ASC LIMIT 50
) union
(SELECT `ofMessageArchive`.*
FROM `ofMessageArchive`
WHERE (ofMessageArchive.toJID = 'user@example.com')
AND `ofMessageArchive`.`messageType` IN ('Message')
AND (ofMessageArchive.sentDate > '1462235333109')
ORDER BY ofMessageArchive.sentDate ASC LIMIT 50
)
) s
order by s.sentDate ASC LIMIT 50