【问题标题】:SQL to find duplicate entries (within a group)SQL 查找重复条目(在组内)
【发布时间】:2010-09-16 00:03:02
【问题描述】:

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 之外,一切都是相同的。

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

【问题讨论】:

  • 您能否举一个包含重复的组的示例并标记应删除哪些行?

标签: sql oracle join


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    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 决定不使用索引,请确保相关人员了解它是索引策略,而不是您编写查询的方式会减慢速度。

    【讨论】:

    • 虽然效率低下。使用解析函数法。
    • 并没有真正测量它,但用了不到一秒
    【解决方案3】:

    该 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)|
    -------------------------------------------------------------------------
    

    【讨论】:

    • 是的,这更像我所期望的。在 oracle 术语中,90K 或 160K 行是非常微不足道的(或至少应该如此)
    • 这就是我自己所期望的,我必须承认我在这里试图帮助一位同事,他在 2 分钟后停止了脚本。不知道为什么要花这么长时间,我的第一个猜测是缺少索引而且我不是 Oracle 专家,所以也许我只是缺少一些信息/设置。
    • 我想,您可能拥有的是陈旧的优化器统计数据,这些数据会误导 Oracle 选择一个糟糕的计划?
    • 试试解析方法的执行计划。
    • 告诉你什么 - 使 groupid 列不为空并对它进行索引可能会在检索记录很少的情况下提高效率。你可能会得到一个索引扫描,驱动一个嵌套循环连接回到表。
    【解决方案4】:

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

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

    【讨论】:

    • DBA 一周不在,否则这是最简单的方法,同意。
    • 你不需要索引来加快速度——你需要一个不同的查询
    【解决方案5】:

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

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

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

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

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

    【讨论】:

    • 问题是缺少索引,而 DBA 目前不在身边,所以这不是解决方案的原因。由于缺少索引,仅子查询大约需要 100 毫秒,乘以 160k 条目,这意味着完整查询大约需要 4-5 小时。我担心真的没有更好的解决方案。
    • 您对优化器的猜测是错误的。它不会需要 160K*0.1 秒,它会更需要 0.1+0.1 秒!
    • 好吧,我们在脚本运行 2 分钟后停止了它
    • 让它运行,看看会发生什么是我的建议。见鬼,如果运行需要 20 分钟,而且它只是让您度过难关,直到您的 dba 回来,那么您可能会发现您将花费更多时间来优化查询,而不是真正值得。
    • 没错,但正如我在另一条评论中所说,我想帮助这里的一位同事,我很好奇是否有更好更快的方法,因为这只是我想出的解决方案几分钟后,我已经有一段时间没有使用 SQL 了。
    【解决方案6】:

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

    select * 
    from group g
    where (select count(*) from event e where g.groupid = e.groupid) <> 5
    

    【讨论】:

      【解决方案7】:

      分析一下:

      SELECT * FROM (
      SELECT eventid, groupid, typeid, COUNT(groupid) OVER (PARTITION BY groupid) group_count
        FROM event
      )
        WHERE group_count <> 5
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-30
        • 1970-01-01
        • 1970-01-01
        • 2022-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多