A
とB
の2つのテーブルがあり、size(A)= size(B)であることがわかっているとします。両方のテーブルのデータが3つの列で同じであることを確認したいのですが、それらがX
、Y
、およびZ
であるとします(テーブルにキーがありません) )。
そのために、私はします:
_ SELECT COUNT(*) FROM
(
Select
X, Y, Z
From
A
)
MINUS
(
Select
X, Y, Z
From
B
)
_
さて、データ間に1つの不一致がある限り、私はcount(*)
の値を知る必要はありません。つまり、値タプルはA
に存在し、B
には存在しません。 、私はテーブルが同一ではないことを知っています。 SQLでこれを言う方法はありますか?つまりMINUSが1つの不一致値に遭遇するとすぐに、それを示すクエリから値を返しますか?
ありがとう!
理論的には、要件とその背後にあるロジックは理にかなっています。ただし、これをどれだけ早く達成できるかは、テーブルAおよびBのデータ量と、有用なインデックスの可用性によって異なります。最悪のシナリオは、テーブルAとBの両方に大量のデータがあり、テーブルで使用できる有用なインデックスがない場合です。その場合(および提供されたテーブル統計が実際のデータに近い場合)、Oracleはカウントを取得するよりも早く「一致しない最初のレコードを見つける」ことができません(クエリを上記のLEFT JOINアプローチに変更した場合)。最良のシナリオは、テーブルAとBの両方、またはテーブルAのデータ量が少ないか、両方のテーブルのX、Y、Z列の組み合わせにインデックスがあるか、のいずれかです。この場合、次のクエリは、COUNTを実行するよりもパフォーマンスが向上する可能性があります
SELECT COUNT(*) FROM DUAL
WHERE NOT EXISTS
(
SELECT NULL
FROM A LEFT JOIN B
ON A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
WHERE B.X IS NULL
) ;
インデックスが利用できない場合に、そのようなクエリをOracleに対してどのように最適化すればよいかわからないが、ここに別の書き直しがある。一致しないタプルの数は計算しませんが、見つかった場合は検索を停止します。
_SELECT 1
FROM dual
WHERE EXISTS
(
Select
X, Y, Z
From
A
MINUS
Select
X, Y, Z
From
B
) ;
_
SQL-Fiddle は、2つのテーブルを最悪の場合完全にスキャンする必要があるため、提供されたすべての回答に対して同様のパフォーマンスを示します。
RolandoとNarendraのクエリは、異なる実行時間(時々より良い、時にはより悪い)を示します、使用されている_HASH JOIN
_のためと思います。
テーブルが大きい場合や、2つのテーブル間の一致が少ない場合や多い場合は、結果が異なる場合があります。 (テストは数K行だけで行われました)。
@Philによって提案されているように、OracleにCOUNT STOPKEY
操作は次のとおりです。
テストベッド:
create table a as
select level x, level y, level z from dual connect by level<=1000000;
--
create table b as
select level+10 x, level+10 y, level+10 z from dual connect by level<=1000000;
count stopkey
クエリ:
select *
from( select *
from a
where not exists (select * from b where x=a.x and y=b.y and z=b.z))
where rownum<=1;
/*
RESULT
------------
Not the same
*/
予定:
Plan hash value: 322064455
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 52 | | 15244 (1)| 00:02:48 |
|* 1 | COUNT STOPKEY | | | | | | |
|* 2 | HASH JOIN ANTI | | 776K| 38M| 18M| 15244 (1)| 00:02:48 |
| 3 | TABLE ACCESS FULL| A | 776K| 9855K| | 5756 (1)| 00:01:04 |
|* 4 | TABLE ACCESS FULL| B | 1018K| 37M| | 5770 (1)| 00:01:04 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=1)
2 - access("X"="A"."X")
4 - filter("Y" IS NOT NULL AND "Z" IS NOT NULL)
Note
-----
- dynamic sampling used for this statement (level=2)
早い段階でミスマッチを起こす可能性が高い場合は、CBOにNESTED LOOPS ANTI
(おそらくこれをNL_AJ
ヒント)。最悪の場合、特にb
での検索を高速化するためのインデックスがない場合、これは大きなテーブルで非常に遅く実行されますが、最良のケースは非常に高速です。
代わりにこれを使用してください:
SELECT X, Y, Z FROM A
MINUS
SELECT X, Y, Z FROM B
UNION ALL
SELECT X, Y, Z FROM B
MINUS
SELECT X, Y, Z FROM A;
これが何も出力しない場合、これらの3つの列は両方のテーブルで同じであることがわかります。