使用ORDER BY datetime

时间:2017-10-12 00:01:53

标签: php mysql date

我有以下在社交网络上运行的查询。该查询从数据库中提取帖子(如Facebook帖子)。

SELECT P.*, 
   P.id_post id_p, 
   PM.meta_content video_title, 
   PM2.meta_content video_views, 
   PM3.meta_content racebooking_views, 
   Greatest(P.creation_date, Coalesce(Max(C.date), P.creation_date)) AS 
   last_activity, 
   P.creation_date creation_date, 
   (SELECT Count(*) 
    FROM   likes 
    WHERE  post_id = P.id_post 
           AND post_type = 'P') 
   likes_count, 
   (SELECT Count(*) 
    FROM   likes L 
    WHERE  post_id = P.id_post 
           AND post_type = 'P' 
           AND L.id_profile = 2796) 
   do_i_like 
FROM   posts P 
       LEFT JOIN comments C 
              ON P.id_post = C.post_id 
                 AND C.post_type = 'P' 
                 AND C.id_profile != P.id_profile 
       LEFT JOIN post_meta PM 
              ON PM.id_post = P.id_post 
                 AND PM.meta_type = 'T' 
       LEFT JOIN post_meta PM2 
              ON PM2.id_post = P.id_post 
                 AND PM2.meta_type = 'V' 
       LEFT JOIN post_meta PM3 
              ON PM3.id_post = P.id_post 
                 AND PM3.meta_type = 'W' 
GROUP  BY P.id_post 
ORDER  BY last_activity DESC 
LIMIT  41, 10 

每篇文章可能有或没有评论。 我希望查询首先获取最近活动的帖子。 所以,如果帖子有评论,我会记下最新评论的日期。如果帖子没有评论,我会接受帖子的创建日期。

作业由Greatest(P.creation_date, Coalesce(Max(C.date), P.creation_date))完成,它会在评论日期(如果存在评论)和帖子创建日期之间获取greates值。

然后,ORDER BY last_activity DESC执行排序作业。

问题

查询真的很慢。运行需要8秒。 posts表有8K行,comments表有8K行。

我不明白的是,如果我用这个ORDER BY P.id_post替换ORDER BY子句,则运行需要0.5秒。但是如果我再次用ORDER BY P.creation_date替换ORDER BY子句则需要8秒。似乎它不喜欢约会...

其他信息

  • posts表在creation_date上有一个索引。
  • 评论表有日期索引
  • 服务器在CentOS Linux 6.6上运行LAMP
  • 我在SO like this one上尝试了其他解决方案,但它们无效

如何修复此查询以更快地运行?

2 个答案:

答案 0 :(得分:2)

select子句中的相关子查询可能会杀死你。相反,加入一个计算喜欢统计数据的子查询:

SELECT P.*, 
    P.id_post id_p, 
    PM.meta_content video_title, 
    PM2.meta_content video_views, 
    PM3.meta_content racebooking_views, 
    GREATEST(P.creation_date, COALESCE(MAX(C.date), P.creation_date)) AS last_activity, 
    P.creation_date creation_date,
    t.likes_count,
    t.do_i_like
FROM posts P
LEFT JOIN
(
    SELECT
        post_id,
        SUM(CASE WHEN post_type = 'P' THEN 1 ELSE 0 END) AS likes_count,
        SUM(CASE WHEN post_type = 'P' AND L.id_profile = 2796
                 THEN 1 ELSE 0 END) AS do_i_like
    FROM likes
    GROUP BY post_id
) t
    ON t.post_id = P.id_post 
LEFT JOIN comments C 
    ON P.id_post = C.post_id AND
       C.post_type = 'P' AND
       C.id_profile != P.id_profile 
LEFT JOIN post_meta PM 
    ON PM.id_post = P.id_post AND
       PM.meta_type = 'T' 
LEFT JOIN post_meta PM2 
    ON PM2.id_post = P.id_post AND
       PM2.meta_type = 'V' 
LEFT JOIN post_meta PM3 
    ON PM3.id_post = P.id_post AND 
       PM3.meta_type = 'W' 
ORDER BY
    last_activity DESC 
LIMIT 41, 10

在编辑查询后,我没有看到在外部查询中使用GROUP BY的原因,所以我删除了它。而你应该在适当的时候使用指数,虽然我的预感是我的建议本身应该会有明显的性能提升。

答案 1 :(得分:0)

有一个MAX(C.Date)需要group by子句,但它也可以替代我认为的子查询:

SELECT P.*, 
    P.id_post id_p, 
    PM.meta_content video_title, 
    PM2.meta_content video_views, 
    PM3.meta_content racebooking_views, 
    GREATEST(P.creation_date, COALESCE(max_c_date, P.creation_date)) AS last_activity, 
    P.creation_date creation_date,
    t.likes_count,
    t.do_i_like
FROM posts P
LEFT JOIN
(
    SELECT
        post_id,
        SUM(CASE WHEN post_type = 'P' THEN 1 ELSE 0 END) AS likes_count,
        SUM(CASE WHEN post_type = 'P' AND L.id_profile = 2796
                 THEN 1 ELSE 0 END) AS do_i_like
    FROM likes
    GROUP BY post_id
) t
    ON t.post_id = P.id_post 
LEFT JOIN (
      SELECT
        comments.post_id,
        MAX(comments.date) max_c_date
      FROM comments
      inner join posts ON comments.post_id = posts.id_post
      where  comments.post_type = 'P' AND
             comments.id_profile != posts.id_profile 
      GROUP BY comments.post_id
) C 
    ON P.id_post = C.post_id AND
LEFT JOIN post_meta PM 
    ON PM.id_post = P.id_post AND
       PM.meta_type = 'T' 
LEFT JOIN post_meta PM2 
    ON PM2.id_post = P.id_post AND
       PM2.meta_type = 'V' 
LEFT JOIN post_meta PM3 
    ON PM3.id_post = P.id_post AND 
       PM3.meta_type = 'W' 
ORDER BY
    last_activity DESC 
LIMIT 41, 10
相关问题