SQL替代在单个表上执行INNER JOIN

时间:2009-08-07 20:56:45

标签: sql mysql performance inner-join

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

表 - TokenFrequency

  • id - int,主键
  • source - int,foreign key
  • token - char
  • count - int

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

  

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

我希望SQL查询为我提供源1,源2以及计数总和。例如:

  

source1 --- source2 --- token --- count
  ---- 2 ----------- 3 --------- cat -------- 4
  ---- 2 ----------- 5 --------- cat -------- 3
  ---- 3 ----------- 5 --------- cat -------- 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
    这不是一个问题,但是如果有办法消除这些问题并反过来获得速度增加那么它将是非常有用的
  3. 我遇到的主要问题是使用当前查询查询的速度需要几个小时才能完成。桌子上的INNER JOIN就是我认为的问题。我确定必须有一种方法来消除内连接,并使用TokenFrequency表的一个实例获得类似的结果。我提到的第二个问题也可能会提高查询的速度。

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

    感谢。

3 个答案:

答案 0 :(得分:2)

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

AND F.source<S.source

答案 1 :(得分:2)

试试这个:

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

这应该运行得更快,也可以消除重复。但是这些来源将以逗号分隔的列表返回,因此您必须在应用程序中将其爆炸。

您也可以尝试在列token, source, count上创建复合索引(按此顺序)并使用EXPLAIN进行分析以查看MySQL是否足够聪明,可以将其用作covering index这个查询。


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

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

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

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

答案 2 :(得分:1)

如果令牌没有编入索引,那当然应该是。