MySQL分组在百万行表上的最大性能问题

时间:2012-07-29 13:43:28

标签: mysql groupwise groupwise-maximum

我正在尝试找到一种直接的方法来提高非常活跃的论坛的性能,其中有大量的帖子和mysql不能再在内存中进行表格排序,并且似乎没有充分利用索引。< / p>

此简单查询查找每个主题中的最新帖子,以便用户确定他们是否有任何回复(稍后通过比较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

然而,当有一百万个帖子并且用户自己拥有数万个帖子时,它的性能就会崩溃。 MySQL可以不再对内存中的表进行排序,也可以扫描太多行。在真实世界中使用它可能需要3秒钟,这是不可接受的imho,因为它在那段时间内飙升CPU并使其他人放慢速度。

我当然可以制作索引的任意组合,但是mysql似乎最喜欢用的是组合

poster_id + post_time 

所以它只选择一个用户的50万个帖子中的百万个,然后按topic_id和排序开始分组。奇怪地将topic_id添加到索引组合中似乎对性能没有帮助,尽管它可能是索引字段的顺序?

我尝试编写一个等效的JOIN,所以我可以使用多个索引但是我遇到的问题是每一方都必须通过post_status和poster过滤。

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

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

感谢您的任何建议!


添加realworld示例和EXPLAIN:

慢日志

# 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

1 个答案:

答案 0 :(得分:2)

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

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)上添加索引后尝试。