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

发布于 2024-12-08 03:37:59 字数 1468 浏览 2 评论 0原文

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

我的(简化的)表,在 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当 SELECT 子句中不存在聚合函数时,BY 行为,这就是为什么我没有放置 GROUP BY 子句而是写了最后一行: AND m.id = (SELECT MAX(id) FROM message WHERE conversation_id = cu.conversation_id)

谢谢!

编辑

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

(第一个问题仍然相关)

I'm programming a private conversation system and need advices on my most complex request.

My (simplified) tables, under 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)

So, I want to display to the user the list of the conversations in which he is participating : for each conversation, I need the conversation id, the conversation subject, the list of participating users, the last message id, the last message author id and username, and the last message date.

I've written this request, which looks pretty bad :

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)

So, I would like to know if you guys see a better way to get the same result ?

I've already read GROUP BY behavior when no aggregate functions are present in the SELECT clause, that's why I didn't put a GROUP BY clause and wrote the last line instead :
AND m.id = (SELECT MAX(id) FROM message WHERE conversation_id = cu.conversation_id)

Thanks !

Edit

I did an EXPLAIN on this request, and there is no KEY used for the JOIN user u ON u.id = cu2.user_id line : why ?

(the first question is still relevant)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鹤舞 2024-12-15 03:37:59

还有其他选择,就像我即将为您提出的那样。但是,老实说,我就是这样做的:)

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的密钥而言,相关的两个表都有索引吗相关领域?

There are alternatives, such as I'm about to put forward for you. But, honestly, that's how I'd do it :)

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

The above allows you to order by DATE or somet other field, and still pick just one message 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

The above avoids a correlated sub-query, and so can (but not always) be faster.

In terms of there be no key being used for JOIN user u ON u.id = cu2.user_id, do both of the two tables in question have indexes on the relevant fields?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文