Запрос в 10 раз медленнее, используя РЕГИСТР ЛЕВОГО СОЕДИНЕНИЯ по порядку

#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 в orderby

Объясните запрос без CASE WHEN n.id IS NULL THEN '0' ELSE '1' END DESC порядка по

Без оператора CASE в порядке

Полный запрос (если это может помочь):

   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. Спасибо за ваш ответ, но это ничего не меняет.