4

SQL 查找重复条目(在组内)

我有一个小问题,我不确定修复它的最佳方法是什么,因为我只能有限地访问数据库 (Oracle) 本身。在我们的表“EVENT”中,我们有大约 160k 个条目,每个 EVENT 都有一个 GROUPID,而一个普通条目正好有 5 行具有相同的 GROUPID。由于一个错误,我们目前得到了几个重复的条目(重复,所以 10 行而不是 5 行,只是一个不同的 EVENTID。这可能会改变,所以它只是 <> 5)。我们需要过滤这些组的所有条目。

由于对数据库的访问受限,我们不能使用临时表,也不能向 GROUPID 列添加索引以使其更快。

我们可以使用此查询获取 GROUPID,但我们需要第二个查询来获取所需的数据

select A."GROUPID"
from "EVENT" A
group by A."GROUPID"
having count(A."GROUPID") <> 5

一种解决方案是子选择:

select *
from "EVENT" A
where A."GROUPID" IN (
  select B."GROUPID"
  from "EVENT" B
  group by B."GROUPID"
  having count(B."GROUPID") <> 5
)

如果没有 GROUPID 和 160k 条目的索引,这需要很长时间。尝试考虑可以处理此问题的连接,但到目前为止找不到好的解决方案。

任何人都可以找到一个好的解决方案吗?

小编辑:我们这里没有 100% 重复,因为每个条目仍然有一个唯一的 ID,而且 GROUPID 也不是唯一的(这就是我们需要使用“分组依据”的原因)——或者我只是错过了一个简单的解决方案它 :)

关于数据的小例子(我不想删除它,只是找到它)

EVENTID | GROUPID | TYPEID
123456    123       12
123457    123       145
123458    123       2612
123459    123       41
123460    123       238

234567    123       12
234568    123       145
234569    123       2612
234570    123       41
234571    123       238

它还有更多列,例如时间戳等,但正如您已经看到的,除了 EVENTID 之外,一切都是相同的。

我们将更频繁地运行它以进行测试,以查找错误并检查它是否再次发生。

4

7 回答 7

6

分析查询要解决的一个经典问题:

select eventid,
       groupid,
       typeid
from   (
       Select eventid,
              groupid,
              typeid,
              count(*) over (partition by group_id) count_by_group_id
       from   EVENT
       )
where count_by_group_id <> 5
于 2008-10-08T13:28:57.427 回答
5

您可以通过联接而不是子查询获得答案

select
    a.*
from
    event as a
inner join
    (select groupid
     from event
     group by groupid
     having count(*) <> 5) as b
  on a.groupid = b.groupid

这是从组中的行中获取所有信息的一种相当常见的方法。

就像您建议的答案和其他回复一样,使用 groupid 上的索引会运行得更快。DBA 需要在使查询运行得更快的好处与维护另一个索引的成本之间取得平衡。

如果 DBA 决定不使用索引,请确保相关人员了解它是索引策略,而不是您编写查询的方式会减慢速度。

于 2008-10-08T13:15:59.060 回答
4

该 SQL 实际需要多长时间?你只会在我假设的情况下运行它,首先修复了导致损坏的错误?我只是设置了一个这样的测试用例:

SQL> create table my_objects as 
  2  select object_name, ceil(rownum/5) groupid, rpad('x',500,'x') filler
  3  from all_objects;

Table created.

SQL> select count(*) from my_objects;

  COUNT(*)
----------
     83782

SQL> select * from my_objects where groupid in (
  2  select groupid from my_objects
  3  group by groupid
  4  having count(*) <> 5
  5  );

OBJECT_NAME                       GROUPID FILLER
------------------------------ ---------- --------------------------------
XYZ                                 16757 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
YYYY                                16757 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Elapsed: 00:00:01.67

不到2秒。好的,我的表的行数是你的一半,但 160K 并不大。我添加了填充列以使表占用一些磁盘空间。AUTOTRACE 执行计划是:

-------------------------------------------------------------------------
| Id  | Operation             | Name       | Rows  | Bytes | Cost (%CPU)|
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |            |   389 |   112K| 14029   (2)|
|*  1 |  HASH JOIN            |            |   389 |   112K| 14029   (2)|
|   2 |   VIEW                | VW_NSO_1   | 94424 |  1198K|  6570   (2)|
|*  3 |    FILTER             |            |       |       |            |
|   4 |     HASH GROUP BY     |            |     1 |  1198K|  6570   (2)|
|   5 |      TABLE ACCESS FULL| MY_OBJECTS | 94424 |  1198K|  6504   (1)|
|   6 |   TABLE ACCESS FULL   | MY_OBJECTS | 94424 |    25M|  6506   (1)|
-------------------------------------------------------------------------
于 2008-10-08T13:12:17.430 回答
2

如果您的 DBA 不会添加索引以加快速度,请询问他们建议您做什么(毕竟这是他们的报酬)。大概您有一个商业案例,为什么您需要此信息,在这种情况下,您的直接管理人员应该站在您这边。

也许您可以要求您的 DBA 将数据复制到可以添加索引的数据库中。

于 2008-10-08T12:53:50.883 回答
2

从 SQL 的角度来看,我认为您已经回答了自己的问题。您描述的方法(即使用子选择)很好,如果任何其他编写查询的方式在性能上差别很大,我会感到惊讶。

160K 记录对我来说似乎并不多。我可以理解如果您对该查询的性能不满意,如果它进入一段应用程序代码,但从它的声音来看,您只是将它用作一些数据清理练习的一部分。(因此希望您在性能方面更加宽容)。

即使没有任何支持索引,它仍然只是对 160K 行进行两次全表扫描,坦率地说,我希望在某种模糊合理的时间内执行。

与您的数据库管理员交谈。他们帮助制造了问题,所以让他们成为解决方案的一部分。

/EDIT/ 同时,运行您的查询。找出需要多长时间,而不是猜测。更好的是运行它,设置自动跟踪,并在此处发布结果,然后我们也许可以帮助您对其进行一些改进。

于 2008-10-08T13:02:46.933 回答
0

这项工作是否符合您的要求,是否提供更好的性能?(我只是想我会把它作为一个建议提出来)。

select * 
from group g
where (select count(*) from event e where g.groupid = e.groupid) <> 5
于 2008-10-08T13:21:17.130 回答
0

怎么分析:

SELECT * FROM (
SELECT eventid, groupid, typeid, COUNT(groupid) OVER (PARTITION BY groupid) group_count
  FROM event
)
  WHERE group_count <> 5
于 2008-10-08T13:26:53.360 回答