7

データ (~100 万エントリ) で明確な名前を見つけるために、次のステートメントがあります。

select Prename, Surname from person p1 
where Prename is not null and Surname is not null 
and not exists (
   select * from person p2 where (p1.Surname = p2.Surname OR p1.Surname = p2.Altname) 
   and p2.Prename LIKE CONCAT(CONCAT('%', p1.Prename), '%') and p2.id <> p1.id
) and inv_date IS NULL

Oracle は 1477315000 という莫大なコストを示し、実行は 5 分後に終了しません。OR を独自の exists サブ句に分割するだけで、パフォーマンスが 0.5 秒に向上し、コストが 45000 に向上します。

select Prename, Surname from person p1 
where Prename is not null and Surname is not null 
and not exists (
   select * from person p2 where p1.Surname = p2.Surname and
   p2.Prename LIKE CONCAT(CONCAT('%', p1.Prename), '%') and p2.id <> p1.id
) and not exists (
   select * from person p2 where p1.Surname = p2.Altname and 
   p2.Prename LIKE CONCAT(CONCAT('%', p1.Prename), '%') and p2.id <> p1.id
) and inv_date IS NULL

これはめったに実行されないクエリであり、CONTACT がどのインデックスよりも優れていることは知っていますが、この高いコストがどこから来るのか疑問に思っています。どちらのクエリも意味的には同等のようです。

4

3 に答える 3

6

答えはあなたの質問のための説明計画にあります。それらは意味的には同等かもしれませんが、クエリの舞台裏での実行プランは大きく異なります。

EXISTSはJOINとは動作が異なり、基本的に、ORフィルターステートメントがテーブルを結合します。

1つのテーブルからレコードを取得するだけなので、2番目のクエリではJOINは発生しません。

于 2011-05-23T14:38:37.230 に答える
2

2 つのクエリの結果は意味的には同等かもしれませんが、実行は操作的に同等ではありません。2 番目の例では、OR 演算子を使用して述語を結合することはありません。2 番目の例のすべての述語は、AND を使用して結合されています。

AND で結合された最初の述語が true と評価されない場合、2 番目 (または他の述語) がスキップされる (評価されない) ため、パフォーマンスが向上します。OR を使用した場合、両方 (またはすべて) の述語を頻繁に評価する必要があるため、クエリが遅くなります。(OR 述語は、いずれかが true と評価されるまでチェックされます。)

于 2011-05-23T14:42:41.873 に答える
1

以下のように書き直されたクエリをテストすることを検討します...一致と見なされるものを「修飾」する基準で一方から他方への直接結合を実行します...次に、WHERE句で、一致しない場合は破棄します。試合を思い付く

select 
      p1.Prename, 
      p1.Surname
   from 
      person p1 
         join person p2
            on p1.ID <> p2.ID
            and (  p1.Surname = p2.Surname
                or p1.SurName = p2.AltName )
            and p2.PreName like concat( concat( '%', p1.Prename ), '%' )
   where
          p1.PreName is not null
      and p1.SurName is not null
      and p1.Inv_date is null
      and p2.id is null

あなたのコメントによると、しかしあなたが探していたように見えるものから...いいえ、左外側の結合をしないでください...あなたがパージしたいのと同じような名前を探しているなら(しかしあなたはそれを処理します)、自己結合(したがって通常の結合)を介して一致するレコードのみを事前認定する必要があります。同じような名前を持たない名前がある場合は、おそらくそのままにしておきます...したがって、結果セットから自動的に除外されます。

さて、WHERE句が始まります...左側に有効な人物がいます...右側に人物がいます..これらは重複しています...したがって、論理的な"をスローすることで一致します。 p2.ID IS NULL "は、NOT EXISTと同じ結果を作成し、最終結果を提供します。

クエリを通常の「結合」に戻します。

于 2011-05-23T14:53:45.473 に答える