我正在尝试找到一种简单的方法来提高非常活跃的论坛的性能,在这些论坛中,帖子数量很多,并且mysql无法再在内存中进行表排序,并且似乎无法充分利用索引。

这个简单的查询查找每个主题中的最新帖子,以供用户确定自此以来是否有任何回复(通过稍后比较topic_time)

SELECT p.*, MAX(post_time) as post_time FROM forum_posts AS p
WHERE p.poster_id = '1' AND p.post_status = '0'
GROUP BY p.topic_id
ORDER BY post_time DESC
LIMIT 50


简单,平坦的桌子看起来像

post_id | poster_id | topic_id | post_status | post_time | post_text


但是,当有100万个帖子并且用户本身拥有数以万计的帖子时,它的性能就会崩溃。 MySQL不能再对内存中的表进行排序,或者扫描的行太多。在现实世界中使用它最多可能需要3秒钟的时间,这是无法接受的,因为在这段时间里它会浪费CPU并降低其他所有人的速度。

我当然可以对索引进行任意组合,但是mysql似乎大多喜欢使用组合

poster_id + post_time


因此,它仅从一百万个用户中选择一个用户的5万个帖子,然后开始按topic_id进行分组和排序。尽管可能是索引字段的顺序,但是奇怪地将topic_id添加到索引混合中似乎并没有帮助提高性能?

我试图写一个等效的JOIN来代替,所以我可以使用多个索引,但是我遇到了一个问题,即必须通过post_status和poster过滤每一面。

我在想,如果至少可以使前几页更快,这样就可以使mysql首先通过post_time通过其索引对数据进行排序,然后开始以降序为用户选择不同的topic_id。我猜这将需要一个子查询,并且不确定50k结果子查询会更好,仍然需要一个临时表。

当然,基本的解决方案将是扩展核心设计,以便有另一个表仅存储每个用户在每个主题中的最大post_time,但这是一个很大的改变,除非找不到其他解决方案。

感谢您的任何建议!



添加真实世界的示例和说明:

慢日志

# Query_time: 2.751334  Lock_time: 0.000056 Rows_sent: 40  Rows_examined: 48286
SELECT   p.*, MAX(post_time) as post_time FROM forum_posts AS p   WHERE p.poster_id = '2' AND p.post_status = '0' GROUP BY p.topic_id  ORDER BY post_time DESC LIMIT 7000, 40;


说明

select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
SIMPLE          p   ref poster_time poster_time 4   const   27072   Using where; Using temporary; Using filesort

最佳答案

首先,修复查询以提供确定的结果:

SELECT p.topic_id,
       MAX(post_time) as post_time
FROM forum_posts AS p
WHERE p.poster_id = '1' AND p.post_status = '0'
GROUP BY p.topic_id
ORDER BY post_time DESC
  LIMIT 50 ;


然后在(post_status, poster_id, topic_id, post_time)上添加索引后尝试。

关于mysql - 百万行表上的MySQL Groupwise最大性能问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11709712/

10-14 12:53
查看更多