#mysql #sql #query-optimization
#mysql #sql #оптимизация запросов
Вопрос:
У меня относительно длинный запрос (размещен ниже для справки).
Я попытался отладить, почему запрос выполняется так медленно (2 секунды), и я, наконец, нашел причину.
В конце запроса я делаю:
ORDER BY
-- order by date
DATE(p.date) DESC,
-- order by followed people
CASE WHEN n.id IS NULL THEN '0' ELSE '1' END DESC -- this case takes the query from 20ms to 2 seconds
Если я удалю регистр order by, он будет выполнен примерно через 20 мс.
Почему это так?
Когда я запускаю запрос с помощью EXPLAIN, я замечаю, что РЕГИСТР добавит «Using temporary» в дополнительное поле.
См. ОБЪЯСНЕНИЕ запросов ниже:
Объясните запрос с CASE WHEN n.id IS NULL THEN '0' ELSE '1' END DESC
помощью in order by
Объясните запрос без CASE WHEN n.id IS NULL THEN '0' ELSE '1' END DESC
порядка по
Полный запрос (если это может помочь):
SELECT
-- feed type
'1' AS feed_type,
-- fetch post data
p.id,
p.receiver,
p.date,
p.message,
p.system_msg,
p.type AS post_type,
-- fetch author data
u.user_id,
u.firstname,
u.lastname,
u.type,
u.permalink,
av.file AS avatar_file,
-- fetch receiever data
u2.user_id AS receiver_user_id,
u2.firstname AS receiver_firstname,
u2.lastname AS receiver_lastname,
u2.permalink AS receiver_permalink,
u2.type AS receiver_type,
-- fetch post comment count
(
SELECT
COUNT(*)
FROM
edu_posts pc
WHERE
pc.comment = p.id
AND pc.deleted IS NULL
) as commentCount,
-- fetch post like count
(
SELECT
COUNT(*)
FROM
edu_likes l
WHERE
l.like_entity = p.id
) as likeCount,
-- user follow state
CASE WHEN n.id IS NOT NULL THEN '1' ELSE '0' END as is_following,
-- check if user likes post
CASE WHEN l.like_id IS NOT NULL THEN '1' ELSE '0' END as user_likes
FROM
edu_posts p
INNER JOIN -- author information
edu_users u ON u.user_id = p.author
LEFT JOIN -- author avatar
edu_avatars av ON av.fk = p.author
AND av.temp = 0
AND av.fk_type = 1
LEFT JOIN -- receiver information (if any)
edu_users u2 ON u2.user_id = p.receiver
LEFT JOIN -- check if author/receiver is followed by current user
edu_notification_list n ON n.user = 1
AND n.following = 1
AND (
n.fk = p.author
OR n.fk = p.receiver
)
AND (
(
n.type = 5
AND p.type = 3
)
OR (
n.type = 2
AND p.type = 1
)
)
LEFT JOIN -- check if user likes the post
edu_likes l ON l.like_entity = p.id
AND l.like_author = 1
WHERE
p.deleted IS NULL
AND p.comment IS NULL
AND (
p.id = p.comment
OR 1 = 1
)
AND (
n.id IS NOT NULL
OR p.system_msg = 0
)
ORDER BY
-- order by date
DATE(p.date) DESC,
-- order by followed people
CASE WHEN n.id IS NULL THEN '0' ELSE '1' END DESC
LIMIT
20 OFFSET 0
ПРИМЕЧАНИЕ: Пожалуйста, дайте мне знать, если вы хотите увидеть какие-либо другие таблицы.
Комментарии:
1. ваше поле второго порядка приводит к использованию MySQL
filesort
. Это плохо. Вы могли бы попробовать предложение @juergen_d и проверить результат EXPLAIN заново.2. Предоставленный им ответ не сработал. У вас есть какие-либо предложения? Я весь день пытался это исправить..
3. Это может быть неуместно, но почему вы сортируете по
DATE(p.date)
, а не поp.date
?4. Потому что я не хочу упорядочивать по времени.
Ответ №1:
Вы выполняете операцию, которая не может использовать индексы. Вместо этого попробуйте
ORDER BY DATE(p.date) DESC,
n.id IS NULL ASC
Комментарии:
1. Спасибо за ваш ответ, но это ничего не меняет.