在范围索引查询后优化GROUP BY

时间:2010-12-29 01:35:21

标签: sql mysql optimization group-by

我有一个内容应用程序需要计算时间片中的响应,然后按响应数量排序。它目前适用于小型数据集,但需要扩展到数百万行。我当前的查询无效。

mysql> describe Responses;
+---------------+---------------------+------+-----+---------+-------+
| Field         | Type                | Null | Key | Default | Extra |
+---------------+---------------------+------+-----+---------+-------+
| site_id       | int(10) unsigned    | NO   | MUL | NULL    |       |
| content_id    | bigint(20) unsigned | NO   | PRI | NULL    |       |
| response_id   | bigint(20) unsigned | NO   | PRI | NULL    |       |
| date          | int(10) unsigned    | NO   |     | NULL    |       |
+---------------+---------------------+------+-----+---------+-------+

表类型是InnoDB,主键是on(content_id,response_id)。在(content_id,date)上有一个额外的索引用于查找对一段内容的响应,另一个索引在(site_id,date)中用于我遇到问题的查询中:

mysql> explain SELECT content_id id, COUNT(response_id) num_responses
               FROM Responses
               WHERE site_id = 1
                 AND date > 1234567890
                 AND date < 1293579867
               GROUP BY content_id
               ORDER BY num_responses DESC
               LIMIT 0, 10;
+----+-------------+-----------+-------+---------------+------+---------+------+------+-----------------------------------------------------------+
| id | select_type | table     | type  | possible_keys | key  | key_len | ref  | rows | Extra                                                     |
+----+-------------+-----------+-------+---------------+------+---------+------+------+-----------------------------------------------------------+
|  1 | SIMPLE      | Responses | range | date          | date | 8       | NULL |  102 | Using where; Using index; Using temporary; Using filesort |
+----+-------------+-----------+-------+---------------+------+---------+------+------+-----------------------------------------------------------+

这是我能够提出的最好的,但它最终会在需要计算的1,000,000行中产生,导致10,000行的排序,以便拉入少数几行结果

由于日期范围是任意的,我无法想到预先计算计数的方法。我有一些更改主键的自由:它可以按任何顺序由content_id,response_id和site_id组成,但不能包含日期。

应用程序主要是用PHP开发的,所以如果有更快的方法通过将查询分成子查询,使用临时表或在应用程序端做事来完成相同的结果,我愿意接受建议。 / p>

3 个答案:

答案 0 :(得分:1)

不是每次计算,如何缓存自上次查询以来计算的计数,并添加计数增量以通过将日期条件放入WHERE子句来更新缓存?

答案 1 :(得分:1)

(根据要求转发自评论)

设置一个包含三列的表:id,date和num_responses。列num_responses包含给定日期的给定id的响应数。适当地回填表格,然后在每晚午夜(或晚上)左右,运行一个脚本,为前一天添加新行。

然后,要获取所需的行,您只需查询上面提到的表。

答案 2 :(得分:0)

您是否考虑过按日期对表格进行分区?桌子上有指数吗?