【问题标题】:SQL: Counting and Numbering Duplicates - Optimising Correlated SubquerySQL:计数和编号重复 - 优化相关子查询
【发布时间】:2015-01-22 19:16:38
【问题描述】:

在 SQLite 数据库中,我有一个表,我需要计算某些列中的重复项(即 3 个特定列相同的行),然后还要对这些情况中的每一个进行编号(即,如果出现 2 次特定的重复,它们需要编号为 1 和 2)。我觉得用文字解释有点困难,所以我将在下面使用一个简化的示例。

我拥有的数据类似于以下(第一行是标题行,表在下面被引用为“idcountdata”):

id  match1  match2  match3  data
1   AbCde   BC      0       data01
2   AbCde   BC      0       data02
3   AbCde   BC      1       data03
4   AbCde   AB      0       data04
5   FGhiJ   BC      0       data05
6   FGhiJ   AB      0       data06
7   FGhiJ   BC      1       data07
8   FGhiJ   BC      1       data08
9   FGhiJ   BC      2       data09
10  HkLMop  BC      1       data10
11  HkLMop  BC      1       data11
12  HkLMop  BC      1       data12
13  HkLMop  DE      1       data13
14  HkLMop  DE      2       data14
15  HkLMop  DE      2       data15
16  HkLMop  DE      2       data16
17  HkLMop  DE      2       data17

我需要为上述生成的输出是:

id  match1  match2  match3  data    matchid  matchcount
1   AbCde   BC      0       data01  1        2
2   AbCde   BC      0       data02  2        2
3   AbCde   BC      1       data03  1        1
4   AbCde   AB      0       data04  1        1
5   FGhiJ   BC      0       data05  1        1
6   FGhiJ   AB      0       data06  1        1
7   FGhiJ   BC      1       data07  1        2
8   FGhiJ   BC      1       data08  2        2
9   FGhiJ   BC      2       data09  1        1
10  HkLMop  BC      1       data10  1        3
11  HkLMop  BC      1       data11  2        3
12  HkLMop  BC      1       data12  3        3
13  HkLMop  DE      1       data13  1        1
14  HkLMop  DE      2       data14  1        4
15  HkLMop  DE      2       data15  2        4
16  HkLMop  DE      2       data16  3        4
17  HkLMop  DE      2       data17  4        4

以前我使用几个相关的子查询来实现这一点,如下所示:

SELECT id, match1, match2, match3, data,
  (SELECT count(*) FROM idcountdata d2 
    WHERE d1.match1=d2.match1 AND d1.match2=d2.match2 AND d1.match3=d2.match3
      AND d2.id<=d1.id)
  AS matchid,
  (SELECT count(*) FROM idcountdata d2 
    WHERE d1.match1=d2.match1 AND d1.match2=d2.match2 AND d1.match3=d2.match3)
  AS matchcount
FROM idcountdata d1;

但是该表有超过 200,000 行(并且数据的长度/内容可以是可变的),因此这需要几个小时才能运行。 (奇怪的是,当我在 2013 年中后期第一次对相同的数据使用相同的查询时,它需要几分钟而不是几小时,但这不是重点——即使在那时我也认为它不优雅且效率低下。)

我已经将上面“matchcount”的相关子查询转换为带有JOIN的不相关子查询,如下所示:

SELECT d1.id, d1.match1, d1.match2, d1.match3, d1.data,
  matchcount
FROM idcountdata d1
JOIN
  (SELECT id,match1,match2,match3,count(*) matchcount 
    FROM idcountdata
    GROUP BY match1,match2,match3) d2
  ON (d1.match1=d2.match1 and d1.match2=d2.match2 and d1.match3=d2.match3);

所以我需要一些帮助来优化它只是“matchid”的子查询。
简而言之,对于较大的数据集,以下查询运行速度太慢:

SELECT id, match1, match2, match3, data,
  (SELECT count(*) FROM idcountdata d2 
    WHERE d1.match1=d2.match1 AND d1.match2=d2.match2 AND d1.match3=d2.match3
      AND d2.id<=d1.id)
  matchid
FROM idcountdata d1;

如何提高上述查询的性能?
它不必在几秒钟内运行,但需要几分钟而不是几小时(大约 200,000 行)。

【问题讨论】:

  • 听起来你已经超越了 sqlite。如果切换数据库是一种选择,请考虑支持row_number
  • ROW_NUMBER with PARTITION link 似乎正是我正在寻找的 - 谢谢。

标签: sql performance sqlite duplicates correlated-subquery


【解决方案1】:

自联接可能比相关子查询更快

SELECT d1.id, d1.match1, d1.match2, d1.match3, d1.data, count(*) matchid
FROM idcountdata d1
JOIN idcountdata d2 on d1.match1 = d2.match1 
  and d1.match2 = d2.match2 
  and d1.match3 = d2.match3
  and d1.id >= d2.id
GROUP BY d1.id, d1.match1, d1.match2, d1.match3, d1.data

此查询可以利用(match1,match2,match3,id) 上的复合索引

【讨论】:

  • 这在几秒钟内适用于我的数据集 - 谢谢!我考虑过自加入,但认为它不会快得多 - 看起来我需要阅读复合索引。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-07
相关资源
最近更新 更多