MySQL 优化子查询并按聚合排序
MySQL Optimize Subquery & Order By Aggregate
我正在收集一些数据(带有主题标签的推文)并努力创建具有以下 table 结构的统计信息:
我的统计目标是显示每条推文有多少 child 和多少印象
查询:
SELECT parent.tweet_id, parent.tweet_text, parent.tweet_time, parent.tweet_image, parent.user_id, parent.user_name, parent.user_follower, parent.user_following, parent.is_retweet, parent.is_favorite, parent.is_reply,
(
SELECT COUNT(tweet_id)
FROM tweet
WHERE tweet_status = 1 && user_follower > 0 && is_retweet = parent.tweet_id
) as child,
(
SELECT (COALESCE(SUM(user_follower),0) + parent.user_follower)
FROM tweet WHERE tweet_status = 1 && user_follower > 0 && is_retweet = parent.tweet_id
) as impression
FROM tweet AS parent
WHERE parent.tweet_status = 1 AND parent.is_retweet = 0 AND parent.is_favorite = 0 AND parent.is_reply = 0
ORDER BY parent.tweet_time DESC
child
:统计推文总数,其中 is_retweet = parent.tweet_id
impression
: parent.user_follower + 总和 user_follewer 其中 is_retweet = parent.tweet_id
我的查询在获取 child
和 impression
时太慢了,我不知道如何优化 :(。但是,真正的问题是当我想根据印象找到前 10 个影响,ORDER BY impression
看傻了
我希望这一切都有助于简化此查询:)
我首先将子查询从 select 列表中移出到派生的 table 的 from 子句中。您只需要一个子查询,因为 2 个子查询具有相同的 where 条件,包括连接条件。派生的 table 应该按 is_retweet 分组,因为它代表 parent-child 关系。显然,select列表中的印象仍然需要计算,因为派生的table只能提供re-tweets的关注者。
SELECT parent.tweet_id, parent.tweet_text, parent.tweet_time, parent.tweet_image, parent.user_id, parent.user_name, parent.user_follower, parent.user_following, parent.is_retweet, parent.is_favorite, parent.is_reply,
COALESCE(t.child,0) as child,
COALESCE(t.sum_child_follower,0) + parent.user_follower as impression
FROM tweet AS parent
LEFT JOIN
(
SELECT is_retweet, COUNT(tweet_id) as child, SUM(user_follower) as sum_child_follower
FROM tweet
WHERE tweet_status = 1 && user_follower > 0
GROUP BY is_retweet
) as t ON t.is_retweet=parent.tweet_id
WHERE parent.tweet_status = 1 AND parent.is_retweet = 0 AND parent.is_favorite = 0 AND parent.is_reply = 0
ORDER BY parent.tweet_time DESC
可以使用适当的索引进一步增强查询,但我没有足够的索引继续进行。但是,外部查询的 where 条件中字段的复合索引似乎是一个很好的起点 - 如果您还没有这样做的话。
遗憾的是,要仅获得前 10 名展示次数,您必须使用按计算展示次数字段和限制子句排序。它不会真正加快查询速度,因为 mysql 必须先计算所有展示次数才能进行排序。
这是您的查询(本质上):
SELECT parent.*,
(SELECT COUNT(*)
FROM tweet t
WHERE t.tweet_status = 1 AND t.user_follower > 0 AND
t.is_retweet = parent.tweet_id
) as child,
(SELECT (COALESCE(SUM(t.user_follower), 0) + parent.user_follower)
FROM tweet t
WHERE t.tweet_status = 1 AND t.user_follower > 0 AND
t.is_retweet = parent.tweet_id
) as impression
FROM tweet AS parent
WHERE parent.tweet_status = 1 AND parent.is_retweet = 0 AND
parent.is_favorite = 0 AND parent.is_reply = 0
ORDER BY parent.tweet_time DESC;
在很多情况下,这可能是编写查询的最佳方式。您需要的是索引:tweet(twee_status, is_retweet, is_vaforite, is_replay, tweet_time, tweet_id)
和 tweet(is_retweet, tweet_status, user_follower)
。我认为这些将删除推文上的任何聚合或排序 table,处理索引中的所有过滤和计算。
我正在收集一些数据(带有主题标签的推文)并努力创建具有以下 table 结构的统计信息:
我的统计目标是显示每条推文有多少 child 和多少印象
查询:
SELECT parent.tweet_id, parent.tweet_text, parent.tweet_time, parent.tweet_image, parent.user_id, parent.user_name, parent.user_follower, parent.user_following, parent.is_retweet, parent.is_favorite, parent.is_reply,
(
SELECT COUNT(tweet_id)
FROM tweet
WHERE tweet_status = 1 && user_follower > 0 && is_retweet = parent.tweet_id
) as child,
(
SELECT (COALESCE(SUM(user_follower),0) + parent.user_follower)
FROM tweet WHERE tweet_status = 1 && user_follower > 0 && is_retweet = parent.tweet_id
) as impression
FROM tweet AS parent
WHERE parent.tweet_status = 1 AND parent.is_retweet = 0 AND parent.is_favorite = 0 AND parent.is_reply = 0
ORDER BY parent.tweet_time DESC
child
:统计推文总数,其中 is_retweet = parent.tweet_id
impression
: parent.user_follower + 总和 user_follewer 其中 is_retweet = parent.tweet_id
我的查询在获取 child
和 impression
时太慢了,我不知道如何优化 :(。但是,真正的问题是当我想根据印象找到前 10 个影响,ORDER BY impression
看傻了
我希望这一切都有助于简化此查询:)
我首先将子查询从 select 列表中移出到派生的 table 的 from 子句中。您只需要一个子查询,因为 2 个子查询具有相同的 where 条件,包括连接条件。派生的 table 应该按 is_retweet 分组,因为它代表 parent-child 关系。显然,select列表中的印象仍然需要计算,因为派生的table只能提供re-tweets的关注者。
SELECT parent.tweet_id, parent.tweet_text, parent.tweet_time, parent.tweet_image, parent.user_id, parent.user_name, parent.user_follower, parent.user_following, parent.is_retweet, parent.is_favorite, parent.is_reply,
COALESCE(t.child,0) as child,
COALESCE(t.sum_child_follower,0) + parent.user_follower as impression
FROM tweet AS parent
LEFT JOIN
(
SELECT is_retweet, COUNT(tweet_id) as child, SUM(user_follower) as sum_child_follower
FROM tweet
WHERE tweet_status = 1 && user_follower > 0
GROUP BY is_retweet
) as t ON t.is_retweet=parent.tweet_id
WHERE parent.tweet_status = 1 AND parent.is_retweet = 0 AND parent.is_favorite = 0 AND parent.is_reply = 0
ORDER BY parent.tweet_time DESC
可以使用适当的索引进一步增强查询,但我没有足够的索引继续进行。但是,外部查询的 where 条件中字段的复合索引似乎是一个很好的起点 - 如果您还没有这样做的话。
遗憾的是,要仅获得前 10 名展示次数,您必须使用按计算展示次数字段和限制子句排序。它不会真正加快查询速度,因为 mysql 必须先计算所有展示次数才能进行排序。
这是您的查询(本质上):
SELECT parent.*,
(SELECT COUNT(*)
FROM tweet t
WHERE t.tweet_status = 1 AND t.user_follower > 0 AND
t.is_retweet = parent.tweet_id
) as child,
(SELECT (COALESCE(SUM(t.user_follower), 0) + parent.user_follower)
FROM tweet t
WHERE t.tweet_status = 1 AND t.user_follower > 0 AND
t.is_retweet = parent.tweet_id
) as impression
FROM tweet AS parent
WHERE parent.tweet_status = 1 AND parent.is_retweet = 0 AND
parent.is_favorite = 0 AND parent.is_reply = 0
ORDER BY parent.tweet_time DESC;
在很多情况下,这可能是编写查询的最佳方式。您需要的是索引:tweet(twee_status, is_retweet, is_vaforite, is_replay, tweet_time, tweet_id)
和 tweet(is_retweet, tweet_status, user_follower)
。我认为这些将删除推文上的任何聚合或排序 table,处理索引中的所有过滤和计算。