mysql - 使用 LEFT JOIN CASE 按顺序查询慢 10 倍

标签 mysql sql query-optimization

我有一个比较长的查询(贴在下面以供引用)。

我尝试调试为什么查询这么慢(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

如果我删除 CASE order by,它将在大约 20 毫秒内执行。

这是为什么?

当我使用 EXPLAIN 运行查询时,我注意到 CASE 会将“Using temporary”添加到 Extra 字段中。

请参阅下面的 EXPLAIN 查询:

按顺序用 CASE WHEN n.id IS NULL THEN '0' ELSE '1' END DESC 解释查询

With the CASE statement in the orderby

解释查询 without CASE WHEN n.id IS NULL THEN '0' ELSE '1' END DESC in order by

Without the CASE statement in the order by

完整查询(如果有帮助的话):

  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

注意:如果您想查看任何其他表格,请告诉我。

最佳答案

您执行的操作无法使用索引。而是尝试

ORDER BY DATE(p.date) DESC, 
         n.id IS NULL ASC

关于mysql - 使用 LEFT JOIN CASE 按顺序查询慢 10 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24326214/

相关文章:

sql - 使用 ADD TABLE 添加列后的 t-SQL UPDATE 表

mysql - 如何标准化实时数据库

mysql - 如何通过 ods 从 phpmyadmin 导入 mysql 数据库中的前导零

php - 如何使用 php 建立下一个和上一个链接?

sql - “列定义不明确”错误

sql - SQL中如何消除重复计算?

mysql - 在 MySQL 中使用组合索引

sql - 添加唯一约束会减慢速度吗?

mysql - 在关系数据库中访问结果时出错

python - 如何在 django 的 sql 查询中进行一般数学运算?