I have created a messaging system for users, it allows them to send a message to another user. If it is the first time they have spoken then a new conversation is initiated,
If you can only have one conversation between users, I don't see a reason for a dedicated conversations table. For this query to work fast, you would need a composite index on (user, message_id)
which is impossible if these fields are in different tables. Move user_id
and friend_id
to the userconversations
. This will make your table 8
bytes per record heavier (even assuming 8
-byte identifiers) which is hardly a problem for a table containing text messages.
If you have few conversations per user with many messages in each, use this:
SELECT um.*
FROM (
(
SELECT MAX(id) AS messageId
FROM usermessages m1
WHERE user_id = :me
GROUP BY
friend_id
ORDER BY
messageId DESC
LIMIT 10
)
UNION ALL
(
SELECT MAX(id) AS messageId
FROM usermessages m1
WHERE frient_id = :me
GROUP BY
user_id
ORDER BY
messageId DESC
LIMIT 10
)
) q
JOIN usermessages um
ON um.id = q.messageId
ORDER BY
id DESC
LIMIT 10
Create separate indexes on user_id
and friend_id
If you have many conversations with few messages in each, use this query:
(
SELECT *
FROM usermessages um
WHERE user_id = :me
AND id =
(
SELECT MAX(id)
FROM usermessages umi
WHERE umi.user_id = um.user_id
AND umi.friend_id = um.friend_id
)
ORDER BY
id DESC
LIMIT 10
)
UNION ALL
(
SELECT *
FROM usermessages um
WHERE frient_id = :me
AND id =
(
SELECT MAX(id)
FROM usermessages umi
WHERE umi.user_id = um.user_id
AND umi.friend_id = um.friend_id
)
ORDER BY
id DESC
LIMIT 10
)
ORDER BY
id DESC
LIMIT 10
The idea behind this query is that it just descends all messages for the given user, checking that each message is the last in its conversation. This may be much faster than sorting all last messages for all conversations (if you have many of them).
For this to work fast, create indexes on
friend_id
user_id, friend_id