需要有关SQL请求的反馈(MySQL,GROUP BY行为)

时间:2011-10-05 14:44:26

标签: mysql sql group-by

我正在编写一个私人会话系统,需要就我最复杂的请求提出建议。

我的(简化)表,在MySQL 5.5下:

user:
    id (int)
    username (string)

conversation:
    id (int)
    subject (string)

conversation_user:
    conversation_id (int)
    user_id (int)

message:
    id (int)
    conversation_id (int)
    user_id (int)
    content (text)
    created_at (datetime)

所以,我想向用户显示他参与的对话列表:对于每个对话,我需要对话ID,对话主题,参与用户列表,最后一个消息ID,最后一个消息作者ID和用户名,以及最后一条消息日期。

我写了这个请求,看起来很糟糕:

SELECT
    cu.conversation_id,
    c.subject,
    u.username,
    m.id,
    m.user_id,
    m.created_at
FROM conversation_user cu
JOIN conversation c ON c.id = cu.conversation_id
JOIN conversation_user cu2 ON cu2.conversation_id = c.conversation_id
JOIN user u ON u.id = cu2.user_id
JOIN message m ON m.conversation_id = cu.conversation_id
WHERE cu.user_id = :current_user_id # the session user_id
AND m.id = (SELECT MAX(id) FROM message WHERE conversation_id = cu.conversation_id)

所以,我想知道你们是否看到了更好的方法来获得相同的结果?

我已经阅读了GROUP BY behavior when no aggregate functions are present in the SELECT clause,这就是为什么我没有放置GROUP BY子句并写下最后一行: AND m.id = (SELECT MAX(id) FROM message WHERE conversation_id = cu.conversation_id)

谢谢!

修改

我对此请求做了一个EXPLAIN,并且没有用于JOIN user u ON u.id = cu2.user_id行的KEY:为什么?

(第一个问题仍然相关)

1 个答案:

答案 0 :(得分:1)

还有其他选择,例如我即将为您提出的。但是,说实话,我就是这样做的。)


AND m.id = (SELECT id FROM message WHERE conversation_id = cu.conversation_id ORDER BY id DESC LIMIT 1)

以上允许您按日期或其他字段订购,并且仍然只选择一个消息ID。


JOIN
  message m
    ON m.conversation_id = cu.conversation_id
JOIN
  (SELECT conversation_id, MAX(id) AS id FROM message GROUP BY conversation_id) AS filter
    ON  filter.conversation_id = cu.conversation_id
    AND filter.id = m.id

以上内容避免了相关的子查询,因此可以(但并非总是)更快。


JOIN user u ON u.id = cu2.user_id没有使用密钥而言,这两个表中的两个在相关字段上都有索引吗?