У меня действительно большой выбор, который немного медленный, и я бы хотел помочь ему улучшить его.
select c.nome, p.foto, c.user, p.user, p.id, p.data, p.titulo, p.youtube, pp.foto, count(DISTINCT likes.user) as likes_count, count(distinct comentarios.id) as comentarios_count, count(DISTINCT l2.user) as count2
from posts p
join cadastro c on p.user=c.id
left join profile_picture pp on p.user = pp.user
left join likes on likes.post = p.id
left join comentarios on comentarios.foto = p.id and comentarios.delete = 0
left join likes l2 on l2.post = p.id and l2.user = ?
where p.user=? and p.delete='0'
group by p.id
order by p.id limit ?
Где я должен добавить индексы для ускорения выбора? во всех полях с on
и where
? например: p.user, c.id, pp.user, p.delete
... не так ли?
Добавьте объединенный индекс в post
в следующем порядке:
post: INDEX(user, delete, id)
profile_picture: (user, foto)
likes: (post, user)
commentarios: (foto, delete, id)
Если я понимаю "пост" и кадастро (реестр), будет ли запись кадастра для каждого сообщения? Поэтому нет необходимости включать кадастро в производную таблицу.
Кроме того, я предполагаю, что на человека есть не более одного фото. (В противном случае GROUP BY
находится в неисправности, а O.Jones не получит правильного ответа.) Есть исправление, если их может быть несколько, но вы хотите показать только одно. (Используйте MAX
.)
Я использую подзапросы в предложении SELECT
, чтобы избежать взрыва-implode JOIN...GROUP BY
.
Я не понимаю, что такое l2.user =?
, но я оставил его в покое.
SELECT c.nome, p.foto, c.user, p.user, p.id, p.data, p.titulo,
p.youtube,
( SELECT MAX(foto) FROM profile_picture
WHERE p.user = user ) AS foto,
( SELECT count(DISTINCT user) FROM likes
WHERE post = p.id ) as likes_count,
( SELECT count(distinct id) FROM comentarios
WHERE foto = p.id
AND delete = 0 ) as comentarios_count,
( SELECT count(DISTINCT user) FROM likes
WHERE post = p.id
AND user = ? ) as count2
FROM
(
SELECT p.id pid
FROM posts p
WHERE p.user=?
and p.delete='0'
ORDER BY p.id
LIMIT ?
) selector
JOIN posts p ON selector.pid = p.id
JOIN cadastro c ON p.user = c.id
ORDER BY p.id
Одним из хороших способов ускорить этот запрос является реорганизация его для отложенного соединения. Цель состоит в том, чтобы выполнить операцию SELECT... ORDER BY... LIMIT...
в наборе результатов с наименьшим количеством столбцов. Почему это важно? Заказ больших наборов результатов дороже, чем заказ небольших, особенно когда LIMIT
отбрасывает большинство результатов заказа.
Итак, начните с этого подзапроса:
SELECT p.id, c.id
FROM posts p
JOIN cadastro c ON p.user=c.id
WHERE p.user=? and p.delete='0'
ORDER BY p.id
LIMIT ?
Там у вас есть соответствующие значения posts.id и cadastro.id для вашего запроса. Вы можете ускорить это с помощью составного индекса покрытия на posts(user, delete)
: планировщик запросов может полностью удовлетворить этот подзапрос от проверки части этого составного индекса.
Затем вы присоединитесь к этой версии вашего основного запроса.
SELECT c.nome, p.foto, c.user, p.user, p.id, p.data, p.titulo,
p.youtube, pp.foto,
count(DISTINCT likes.user) as likes_count,
count(distinct comentarios.id) as comentarios_count,
count(DISTINCT l2.user) as count2
FROM (
SELECT p.id pid, c.id cid
FROM posts p
JOIN cadastro c ON p.user=c.id
WHERE p.user=? and p.delete='0'
ORDER BY p.id, c.id
LIMIT ?
) selector
JOIN posts p ON selector.pid = p.id
JOIN cadastro c ON selector.cid = p.user
left join profile_picture pp on p.user = pp.user
left join likes on likes.post = p.id
left join comentarios on comentarios.foto = p.id and comentarios.delete = 0
left join likes l2 on l2.post = p.id and l2.user = ?
where p.user=? and p.delete='0'
group by p.id
order by p.id limit ?
Вам нужно переделать ORDER BY... LIMIT?
потому что ваши левые соединения могут увеличить размер конечного набора результатов, и вам нужно ограничить его.
Трудно сказать, какие индексы ускорят оставшуюся часть запроса без дополнительной информации о ваших таблицах. Все эти операции COUNT (DISTINCT...) неизбежно несколько дороги. Вам может быть полезно прочитать это: https://use-the-index-luke.com/
Pro tip Вы используете и, возможно, неправильно используете пресловутое расширение GROUP BY
в MySQL. Ваша GROUP BY
должна сказать это, или значения c.nome
и c.user
могут быть выбраны непредсказуемым образом.
GROUP BY p.id, c.id
Pro tip Одноколоночные индексы обычно не помогают в запросах или подзапросах: MySQL может использовать только один индекс для каждой таблицы в запросе. Таким образом, покрытие индексов столбцами в правильном порядке может помочь. Не просто вставляйте кучу индексов в надежде ускорить запросы.
limit
или это только первый образец нумерации страниц, чтобы позже получить другие части со смещением?