Как ускорить этот запрос MySQL? Запрос последних сообщений

Мне нужно ускорить этот запрос для списка последних сообщений. Этот запрос выполняется слишком долго (например, 10 секунд …)

SELECT datas.uid,
datas.message,
datas.date,
CONCAT(conv.first_name, ' ', conv.last_name) AS conversation_name
FROM   (SELECT m.message_id,
m.message,
IF (m.from_uid = 1, m.to_uid, m.from_uid) AS uid,
m.readed,
m.sended                                  AS `date`
FROM   users u
LEFT JOIN messages m
ON m.from_uid = u.user_id
WHERE  m.message_id IN (SELECT MAX(message_id)
FROM   messages
WHERE  to_uid = 1
OR from_uid = 1
GROUP  BY LEAST(from_uid, to_uid),
GREATEST(from_uid, to_uid))) datas
LEFT JOIN users conv
ON conv.user_id = datas.uid
ORDER  BY datas.date DESC
LIMIT  5

В этом запросе используются 2 таблицы (пользователи и сообщения).
Таблица пользователей:

  • user_id (основной, автоинкремент)
  • авторизоваться
  • проходить
  • имя
  • Фамилия
  • ….

Табличные сообщения:

  • message_id (основной, автоинкремент)
  • from_uid (сообщение отправителя, ссылка на пользователей таблицы -> user_id)
  • to_uid (сообщение получателя, ссылка на пользователей таблицы -> user_id)
  • отправлено (отметка времени)
  • сообщение (varchar)

РЕДАКТИРОВАТЬ
Я добавил индексы к сообщениям:
— from_uid
— to_uid
— отправил

и это без эффекта …

-1

Решение

Попробуйте создать проиндексированный идентификатор, который вы проверяете.

В этом случае вы можете создать индекс для: conv.user_id, datas.uid, m.message_id, messages.to_uid, messages.from_uid и datas.date, что также может быть хорошей идеей, так как вы сортируете по тот.

0

Другие решения

Добавить индексы на from_uid а также to_uid ускорить SELECT MAX(message_id) подзапрос. В противном случае он должен сделать полное сканирование таблицы.

0

Я хотел бы попытаться удалить подзапрос (ы)

Вы можете немного его очистить, дважды присоединяясь к пользователям, когда получаете данные пользователя от te и до uid. Таким образом, объединения могут эффективно использовать индексы. Затем просто используйте IF в SELECT, чтобы решить, какой из них вернуть: —

SELECT IF (m.from_uid = 1, m.to_uid, m.from_uid) AS uid,
m.message,
m.sended AS `date`,
IF (m.from_uid = 1, CONCAT(to_conv.first_name, ' ', to_conv.last_name), CONCAT(from_conv.first_name, ' ', from_conv.last_name)) AS conversation_name
FROM   users u
LEFT JOIN messages m
ON m.from_uid = u.user_id
LEFT JOIN users to_conv
ON to_conv.user_id = m.to_uid
LEFT JOIN users from_conv
ON from_conv.user_id = m.from_uid
WHERE  m.message_id IN
(
SELECT MAX(message_id)
FROM   messages
WHERE  to_uid = 1
OR from_uid = 1
GROUP  BY LEAST(from_uid, to_uid),
GREATEST(from_uid, to_uid)
)
ORDER  BY date DESC
LIMIT  5

Подзапрос для проверки идентификатора сообщения удалить немного сложнее. Вообще IN работает плохо. Возможно, стоит изменить его на использование EXISTS (хотя для этого потребуется проверка в предложении HAVING, что может быть не очень хорошо)

SELECT IF (m.from_uid = 1, m.to_uid, m.from_uid) AS uid,
m.message,
m.sended AS `date`,
IF (m.from_uid = 1, CONCAT(to_conv.first_name, ' ', to_conv.last_name), CONCAT(from_conv.first_name, ' ', from_conv.last_name)) AS conversation_name
FROM   users u
LEFT JOIN messages m
ON m.from_uid = u.user_id
LEFT JOIN users to_conv
ON to_conv.user_id = m.to_uid
LEFT JOIN users from_conv
ON from_conv.user_id = m.from_uid
WHERE  EXISTS
(
SELECT MAX(message_id) AS max_message_id
FROM   messages
WHERE  to_uid = 1
OR from_uid = 1
GROUP  BY LEAST(from_uid, to_uid), GREATEST(from_uid, to_uid)
HAVING m.message_id = max_message_id
)
ORDER  BY date DESC
LIMIT  5
0
По вопросам рекламы [email protected]