4

我在优化查询时遇到了困难,例如

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. 狮身人面像,但我不确定它是否有助于这些类型的查询。

此外,是否有任何 OLAP 多维数据集实现可以优化此类查询?

4

3 回答 3

1

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

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

我要做的是对前 K 个进行紧凑表示,当新项目进入时更新它。对于每个元素,获取它的分数,并保留迄今为止看到的前 K 个元素的堆。

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

具体解决方案

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

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

  • 使用上面的流式方法,将每个分数列的前 450 名分别保存在堆中
  • 在查询时,按列获取与查询匹配的项目
  • 根据需要对列表进行聚合和排序,并在 450 处剪切

希望能帮助到你。

于 2011-08-11T22:39:51.967 回答
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; 
于 2011-08-12T00:03:00.070 回答
1

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

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

于 2011-08-11T07:51:11.550 回答