优化前N个查询

时间:2011-08-11 07:47:13

标签: mysql sphinx olap-cube

我很难优化像

这样的查询
SELECT RESULT_ID FROM RESULTS 
WHERE SOURCE = 1 AND GROUP=2 AND SCORE1 BETWEEN 20 AND 100 
ORDER BY SCORE2 LIMIT 450; 

在4000万行innodb表上。该查询可能需要排序多达1500万个结果才能获得前450名。到目前为止,我已尝试过:

  1. 定义索引,但那些不习惯排序因为MySQL 在范围条件之后忽略索引中的任何列。因为我们 有一堆得分列,我们可以获得范围条件 他们的数量,然后对特定的分数进行排序 将结果集限制在前450位。
  2. 使用内存表,但在排序如此大的结果时效果不佳。
  3. Sphinx,但我不确定它是否有助于这些类型的查询。
  4. 此外,是否有任何可以优化这类查询的OLAP多维数据集实现?

3 个答案:

答案 0 :(得分:1)

我建议创建一个包含这450行的单独表,并在每次插入新行或更新旧行时计算,并参考另一个表。

这样您的查询就不需要每次都浏览所有行。

答案 1 :(得分:1)

您可以预先指定通用分数范围。例如,您可以创建几种类型的范围:

                1          2           3           4
RANGE_50  = { 0..50,    51..100,   101..150,   151..200 }
RANGE_100 = { 0..100,   101..200                        }
RANGE_200 = { 0..200                                    }

这些范围类型可以在表格中创建为列,并且必须根据 score1 的值进行更新。

然后你就可以使用这样的查询:

SELECT RESULT_ID FROM RESULTS 
WHERE SOURCE = 1 AND GROUP=2 AND RANGE_100 = 2 
ORDER BY SCORE2 LIMIT 450; 

答案 2 :(得分:0)

你正在寻找的东西,恕我直言,是一种在(理论上)无限流的项目中获得前K项的方法。

我不会尝试直接在mysql中解决这个问题,因为您的输入是流而不是固定数据集。此外,考虑到数据集大小,在每个插入上从头开始重新计算顶部K是不可能的。

我要做的是在新项目进入时更新顶部K的紧凑表示。对于每个元素,取其得分,并保留到目前为止看到的顶部K元素的堆。

更正式一点:给定数据流q1 ,. 。 。 ,qn,如果Score(qj)大于堆中的最小分数,则将qj添加到堆中。在这种情况下,应该从堆中逐出最小的估计分数。

具体解决方案

您有多个分数列,用户可以使用范围查询向前450名询问任何列组合。

从概念上讲,我会做的是:

  • 使用上面的流媒体方法
  • 分别为每个得分列保留前450个堆
  • 在查询时,获取与列查询匹配的项目
  • 根据需要对列表进行聚合和排序,并在450
  • 处剪切

希望它有所帮助。