Нужна обратная связь по запросу SQL (MySQL, поведение GROUP BY) - PullRequest
1 голос
/ 05 октября 2011

Я программирую систему частных бесед и нуждаюсь в советах по моему сложному запросу.

Мои (упрощенные) таблицы под 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)

Итак, я хочу отобразить пользователю список разговоров, в которых он участвует: для каждого разговора мне нужен идентификатор разговора, тема разговора, список участвующих пользователей, идентификатор последнего сообщения, последнее идентификатор автора сообщения, имя пользователя и дата последнего сообщения.

Я написал этот запрос, который выглядит довольно плохо:

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, когда в предложении SELECT нет агрегатных функций , поэтому я не поместил предложение 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 Ответ

1 голос
/ 05 октября 2011

Есть альтернативы, которые я собираюсь предложить вам.Но, честно говоря, вот как я это сделаю:)


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 не используется ключ, имеют ли обе из двух рассматриваемых таблиц индексы в соответствующих полях?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...