将JOIN查询重写为子查询,缺少行?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了将JOIN查询重写为子查询,缺少行?相关的知识,希望对你有一定的参考价值。

我有以下mysql查询返回这些行:

SELECT p.ID AS id, p.post_title AS title, p.post_author AS uid, SUM(v.pageviews) AS pageviews, IFNULL(c.comment_count, 0) AS comment_count 
FROM `views` v 
LEFT JOIN `posts` p ON v.postid = p.ID 
LEFT JOIN (SELECT comment_post_ID, COUNT(comment_post_ID) AS comment_count FROM `comments` WHERE comment_date_gmt > DATE_SUB('2018-08-16 18:34:46', INTERVAL 29 DAY) AND comment_approved = 1 GROUP BY comment_post_ID) c ON p.ID = c.comment_post_ID 
WHERE 1 = 1 AND p.post_type IN('post') AND v.view_datetime > DATE_SUB('2018-08-16 18:34:46', INTERVAL 29 DAY) AND p.post_password = '' AND p.post_status = 'publish' GROUP BY v.postid ORDER BY pageviews DESC LIMIT 5 OFFSET 0;

JOIN query

我目前正在尝试使用子查询而不是JOIN来重写它,以检查性能是否更好。

以下查询返回相同的结果(comment_count列除外,因为我们只查询两个表而不是三个表):

SELECT p.ID AS id, p.post_title AS title, p.post_author AS uid, v.pageviews AS pageviews 
FROM `posts` p,
    (SELECT SUM(pageviews) AS pageviews, postid FROM `views` WHERE view_datetime > DATE_SUB( '2018-08-16 18:34:46', INTERVAL 29 DAY) GROUP BY postid) v
WHERE 1 = 1 AND p.ID = v.postid AND p.post_type IN('post') AND p.post_password = '' AND p.post_status = 'publish' GROUP BY v.postid ORDER BY pageviews DESC LIMIT 5 OFFSET 0

subqueries query

但是,如果我将comments表添加到混合中,则会自动排除没有注释的帖子(例如ID为2956且包含3100个视图),与原始查询相比返回不同的结果:

SELECT p.ID AS id, p.post_title AS title, p.post_author AS uid, v.pageviews AS pageviews, IFNULL(c.comment_count, 0) AS comment_count 
FROM `posts` p,
    (SELECT SUM(pageviews) AS pageviews, postid FROM `views` WHERE view_datetime > DATE_SUB( '2018-08-16 18:34:46', INTERVAL 29 DAY) GROUP BY postid) v,
    (SELECT COUNT(comment_post_ID) AS comment_count, comment_post_ID FROM `comments` WHERE comment_date_gmt > DATE_SUB('2018-08-16 18:34:46', INTERVAL 29 DAY) AND comment_approved = 1 GROUP BY comment_post_ID) c 
WHERE 1 = 1 AND p.ID = v.postid AND v.postid = c.comment_post_ID AND p.post_type IN('post') AND p.post_password = '' AND p.post_status = 'publish' GROUP BY v.postid ORDER BY pageviews DESC LIMIT 5 OFFSET 0

subqueries query with comments table

我对这些东西并不是很有经验(正如你所知道的那样),所以任何有助于理解正在发生的事情的帮助/提示都会非常感激。

答案

正如我在评论中提到的,您的新查询仍然有JOIN。如果你想使用子查询测试性能,你需要将查询更改为这样的(这是我根据你的原始工作查询的最佳猜测;没有看到表结构和数据,很难100%确定):

SELECT id, post_title AS title, post_author AS uid, 
    (SELECT SUM(pageviews) 
     FROM views v 
     WHERE v.postid = posts.id AND 
           v.view_datetime > DATE_SUB('2018-08-16 18:34:46', INTERVAL 29 DAY)
    ) AS pageviews,
    (SELECT COUNT(comment_post_ID) 
     FROM comments c 
     WHERE c.comment_post_ID = posts.id AND
           c.comment_date_gmt > DATE_SUB('2018-08-16 18:34:46', INTERVAL 29 DAY) AND 
           c.comment_approved = 1
    ) AS comment_count
FROM posts
WHERE p.post_type IN('post') AND p.post_password = '' AND p.post_status = 'publish'
ORDER BY pageviews DESC 
LIMIT 5 OFFSET 0;

以上是关于将JOIN查询重写为子查询,缺少行?的主要内容,如果未能解决你的问题,请参考以下文章

查询包含多个 JOIN 时访问 SQL 语法错误(缺少运算符)

将这些 DB2 SUBQUERY 重写为 Join

在 JOIN 中重写慢速 SQL(子)查询

关于子查询

在 WHERE 子句中使用 OR 的慢速 JOIN 查询 - 缺少可能的索引?

如何在不破坏SQL逻辑的情况下将JOINS转换为子查询