web-dev-qa-db-ja.com

比較クエリの最適化

ABの2つのテーブルがあり、size(A)= size(B)であることがわかっているとします。両方のテーブルのデータが3つの列で同じであることを確認したいのですが、それらがXY、およびZであるとします(テーブルにキーがありません) )。

そのために、私はします:

_ SELECT COUNT(*) FROM
     (
        Select
            X, Y, Z
        From
            A
     )
     MINUS
     (
        Select
            X, Y, Z
        From
            B
     )
_

さて、データ間に1つの不一致がある限り、私はcount(*)の値を知る必要はありません。つまり、値タプルはAに存在し、Bには存在しません。 、私はテーブルが同一ではないことを知っています。 SQLでこれを言う方法はありますか?つまりMINUSが1つの不一致値に遭遇するとすぐに、それを示すクエリから値を返しますか?

ありがとう!

6
0x4B1D

理論的には、要件とその背後にあるロジックは理にかなっています。ただし、これをどれだけ早く達成できるかは、テーブル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
) ;
2
Narendra

インデックスが利用できない場合に、そのようなクエリを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行だけで行われました)。

4
ypercubeᵀᴹ

@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つの列は両方のテーブルで同じであることがわかります。

0
g00dy