Индексы в большом выборе - mysql - PullRequest
0 голосов
/ 04 мая 2018

У меня действительно большой выбор, который немного медленный, и мне нужна помощь, чтобы улучшить его.

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 ... не слишком ли много?

Ответы [ 2 ]

0 голосов
/ 19 мая 2018

Добавить составной индекс для post, в этом порядке :

post:  INDEX(user, delete, id)
profile_picture:  (user, foto)
likes:  (post, user)
commentarios:  (foto, delete, id)

Если я понимаю слова "запись" и кадастр (реестр), будет ли запись в кадастре для каждого сообщения? Поэтому нет необходимости включать кадастр в производную таблицу.

Кроме того, я полагаю, что на каждого человека может быть не более одной фотографии. (В противном случае GROUP BY окажется в беде, и О. Джонс не получит правильный ответ.) Существует исправление, если может быть более одного, но вы хотите показать только один. (Используйте MAX.)

Я использую подзапросы в предложении SELECT, чтобы избежать взрыва-взрыва 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
0 голосов
/ 04 мая 2018

Хороший способ ускорить этот запрос - это реорганизовать его для выполнения отложенного соединения . Цель состоит в том, чтобы выполнить операцию 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 может использовать только один индекс на таблицу в запросе. Таким образом, покрытие индексов столбцами в правильном порядке может сильно помочь. Не надо просто добавлять кучу индексов в надежде ускорить запросы.

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