4

重複するエントリを検索するSQL(グループ内)

私には小さな問題があり、データベース(Oracle)自体へのアクセスが制限されているため、それを修正するための最良の方法がわかりません。テーブル「EVENT」には約16万のエントリがあり、各EVENTにはGROUPIDがあり、通常のエントリには同じGROUPIDを持つ正確に5つの行があります。バグが原因で、現在、いくつかの重複エントリが取得されています(重複しているため、5行ではなく10行で、EVENTIDが異なります。これは変更される可能性があるため、<> 5です)。これらのグループのすべてのエントリをフィルタリングする必要があります。

データベースへのアクセスが制限されているため、一時テーブルを使用することも、GROUPID列にインデックスを追加して高速化することもできません。

このクエリでGROUPIDを取得できますが、必要なデータを取得するには2番目のクエリが必要になります

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

1つの解決策は、副選択です。

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も一意ではないためです(そのため、「group by」を使用する必要があります)。それ :)

データに関する小さな例(削除したくないので、見つけてください)

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秒未満。OK、私のテーブルにはあなたのテーブルの半分の行がありますが、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 に何を提案するか尋ねてください (結局のところ、DBA はそれに対して報酬を支払っています)。おそらく、あなたはなぜこの情報が必要なのかというビジネス上の理由があると思われます。

おそらく、DBA に、インデックスを追加できるデータベースにデータを複製するよう依頼することができます。

于 2008-10-08T12:53:50.883 に答える
2

SQL の観点からは、あなたはすでに自分の質問に答えていると思います。あなたが説明したアプローチ(つまり、サブセレクトを使用する)は問題ありません。クエリを作成する他の方法でパフォーマンスが大幅に異なる場合は驚くでしょう。

160K レコードは、私には多くのようには思えません。そのクエリがアプリケーション コードの一部である場合、そのクエリのパフォーマンスに不満があるかどうかは理解できますが、その音からすると、データ クレンジングの演習の一部として使用しているだけです。(したがって、パフォーマンスに関してもう少し寛容であることが期待されます)。

サポートするインデックスがなくても、160,000 行の全テーブル テーブル スキャンを 2 回実行するだけで済みます。

データベース管理者に相談してください。彼らは問題の作成に貢献したので、解決策の一部にしましょう。

/EDIT/ それまでの間、クエリを実行してください。推測するのではなく、所要時間を調べてください。set autotrace をオンにして実行し、結果をここに投稿することをお勧めします。

于 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 に答える