6

我有一个大表(TokenFrequency),其中有数百万行。TokenFrequency 表的结构如下:

表 - TokenFrequency

  • id - int,主键
  • 源 - 整数,外键
  • 令牌 - 字符
  • 计数 - 整数

我的目标是选择其中两个来源具有相同标记的所有行。例如,如果我的表看起来像这样:

id --- source --- token --- count
1 ------ 1 --------- dog ------- 1
2 ------ 2 --- ------ 猫 -------- 2
3 ------ 3 --------- 猫 -------- 2
4 ------ 4 --------- 猪 -------- 5
5 ------ 5 --------- 动物园 ------- 1
6 --- --- 5 --------- 猫 -------- 1
7 ------ 5 --------- 猪 -------- 1

我想要一个 SQL 查询来给我源 1、源 2 和计数的总和。例如:

source1 --- source2 --- token --- count
---- 2 ----------- 3 --------- cat -------- 4
- --- 2 ----------- 5 --------- 猫 -------- 3
---- 3 ---------- - 5 --------- 猫 -------- 3
---- 4 ----------- 5 --------- 猪 -- ------ 6

我有一个看起来像这样的查询:

SELECT  F.source AS source1, S.source AS source2, F.token, 
       (F.count + S.count) AS sum 
FROM       TokenFrequency F 
INNER JOIN TokenFrequency S ON F.token = S.token 
WHERE F.source <> S.source

此查询工作正常,但我遇到的问题是:

  1. 我有一个包含数百万行的 TokenFrequency 表,因此需要更快的替代方法来获得此结果。
  2. 我当前的查询是重复的。例如它的选择:
    source1=2, source2=3, token=cat, count=4
    source1=3, source2=2, token=cat, count=4
    这不是太大的问题,但如果有办法消除这些并反过来获得速度增加,那么这将非常有用

我遇到的主要问题是当前查询的查询速度需要数小时才能完成。我认为自己的表上的 INNER JOIN 是问题所在。我确信必须有一种方法来消除内部连接并仅使用 TokenFrequency 表的一个实例来获得类似的结果。我提到的第二个问题也可能会促进查询速度的提高。

我需要一种方法来重组这个查询,以更快、更有效的方式提供相同的结果。

谢谢。

4

3 回答 3

3

我需要更多信息来诊断速度问题,但要删除 dups,请将其添加到 WHERE:

AND F.source<S.source
于 2009-08-07T21:05:25.350 回答
3

尝试这个:

SELECT token, GROUP_CONCAT(source), SUM(count)
FROM TokenFrequency
GROUP BY token;

这应该运行得更快,并消除重复。但是源将以逗号分隔的列表形式返回,因此您必须在应用程序中展开该列表。

您也可以尝试在列上创建复合索引token, source, count(按该顺序)并分析EXPLAIN以查看 MySQL 是否足够聪明以将其用作此查询的覆盖索引


更新:我似乎误解了你的问题。您不想要每个令牌的计数总和,您想要给定令牌的每对源的计数总和。

我相信内部连接是最好的解决方案。SQL 的一个重要准则是,如果您需要针对两个不同的行计算一个表达式,那么您需要进行连接。

但是,我上面提到的一种优化技术是使用覆盖索引,以便您需要的所有列都包含在索引数据结构中。好处是您的所有查找都是 O(log n),并且查询不需要执行第二次 I/O 来读取物理行来获取其他列。

token, source, count在这种情况下,您应该如上所述在列上创建覆盖索引。还要尝试分配足够的缓存空间,以便索引可以缓存在内存中。

于 2009-08-07T21:06:33.383 回答
2

如果 token 没有被索引,它当然应该被索引。

于 2009-08-07T21:17:42.050 回答