5

結合が内部でどのように機能するかを理解しようとしています。次の 2 つのクエリの実行方法の違いは何ですか?

For example

(A)

Select * 
FROM TABLE1
FULL JOIN TABLE2 ON TABLE1.ID = TABLE2.ID
FULL JOIN TABLE3 ON TABLE1.ID = TABLE3.ID

And

(B)

Select * 
FROM TABLE1
FULL JOIN TABLE2 ON TABLE1.ID = TABLE2.ID
FULL JOIN TABLE3 ON TABLE2.ID = TABLE3.ID

編集:ここではオラクルについて話しています。テーブル 2 とテーブル 3 には存在するが、テーブル 1 には存在しないいくつかのレコードがあるとします。クエリ A はそのレコードに対して 2 つの行を提供しますが、B は 1 つの行しか提​​供しません。

4

4 に答える 4

9

DBMS のオプティマイザは、クエリを実行する最善の方法を決定します。通常、これは「コスト ベースの最適化」によって行われ、さまざまなクエリ プランが考慮され、最も効率的なプランが選択されます。 2 つのクエリが論理的に同一である場合、どのように記述しても、オプティマイザーは同じクエリ プランを使用する可能性が高くなります。実際、SQL のこのようなわずかな違いに基づいて異なるクエリ プランを生成するのは、最近では不十分なオプティマイザです。

ただし、列が結合される方法が結果に影響するため、完全外部結合は別の問題です (少なくとも Oracle では)。つまり、2 つのクエリは交換できません。

SQL Plus で AUTOTRACE を使用して、さまざまな計画を確認できます。

SQL> select *
  2  from t1
  3  full join t2 on t2.id = t1.id
  4  full join t3 on t3.id = t2.id;

        ID         ID         ID
---------- ---------- ----------
                    1          1

1 row selected.


Execution Plan
----------------------------------------------------------

---------------------------------------------------------------------
| Id  | Operation               | Name | Rows  | Bytes | Cost (%CPU)|
---------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |     3 |   117 |    29  (11)|
|   1 |  VIEW                   |      |     3 |   117 |    29  (11)|
|   2 |   UNION-ALL             |      |       |       |            |
|*  3 |    HASH JOIN OUTER      |      |     2 |   142 |    15  (14)|
|   4 |     VIEW                |      |     2 |    90 |    11  (10)|
|   5 |      UNION-ALL          |      |       |       |            |
|*  6 |       HASH JOIN OUTER   |      |     1 |    91 |     6  (17)|
|   7 |        TABLE ACCESS FULL| T1   |     1 |    52 |     2   (0)|
|   8 |        TABLE ACCESS FULL| T2   |     1 |    39 |     3   (0)|
|*  9 |       HASH JOIN ANTI    |      |     1 |    26 |     6  (17)|
|  10 |        TABLE ACCESS FULL| T2   |     1 |    13 |     3   (0)|
|  11 |        TABLE ACCESS FULL| T1   |     1 |    13 |     2   (0)|
|  12 |     TABLE ACCESS FULL   | T3   |     1 |    26 |     3   (0)|
|* 13 |    HASH JOIN ANTI       |      |     1 |    26 |    15  (14)|
|  14 |     TABLE ACCESS FULL   | T3   |     1 |    13 |     3   (0)|
|  15 |     VIEW                |      |     2 |    26 |    11  (10)|
|  16 |      UNION-ALL          |      |       |       |            |
|* 17 |       HASH JOIN OUTER   |      |     1 |    39 |     6  (17)|
|  18 |        TABLE ACCESS FULL| T1   |     1 |    26 |     2   (0)|
|  19 |        TABLE ACCESS FULL| T2   |     1 |    13 |     3   (0)|
|* 20 |       HASH JOIN ANTI    |      |     1 |    26 |     6  (17)|
|  21 |        TABLE ACCESS FULL| T2   |     1 |    13 |     3   (0)|
|  22 |        TABLE ACCESS FULL| T1   |     1 |    13 |     2   (0)|
---------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("T3"."ID"(+)="T2"."ID")
   6 - access("T2"."ID"(+)="T1"."ID")
   9 - access("T2"."ID"="T1"."ID")
  13 - access("T3"."ID"="T2"."ID")
  17 - access("T2"."ID"(+)="T1"."ID")
  20 - access("T2"."ID"="T1"."ID")

SQL> select *
  2  from t1
  3  full join t2 on t2.id = t1.id
  4  full join t3 on t3.id = t1.id;

        ID         ID         ID
---------- ---------- ----------
                    1
                               1

2 rows selected.


Execution Plan
----------------------------------------------------------

---------------------------------------------------------------------
| Id  | Operation               | Name | Rows  | Bytes | Cost (%CPU)|
---------------------------------------------------------------------
|   0 | SELECT STATEMENT        |      |     3 |   117 |    29  (11)|
|   1 |  VIEW                   |      |     3 |   117 |    29  (11)|
|   2 |   UNION-ALL             |      |       |       |            |
|*  3 |    HASH JOIN OUTER      |      |     2 |   142 |    15  (14)|
|   4 |     VIEW                |      |     2 |    90 |    11  (10)|
|   5 |      UNION-ALL          |      |       |       |            |
|*  6 |       HASH JOIN OUTER   |      |     1 |    91 |     6  (17)|
|   7 |        TABLE ACCESS FULL| T1   |     1 |    52 |     2   (0)|
|   8 |        TABLE ACCESS FULL| T2   |     1 |    39 |     3   (0)|
|*  9 |       HASH JOIN ANTI    |      |     1 |    26 |     6  (17)|
|  10 |        TABLE ACCESS FULL| T2   |     1 |    13 |     3   (0)|
|  11 |        TABLE ACCESS FULL| T1   |     1 |    13 |     2   (0)|
|  12 |     TABLE ACCESS FULL   | T3   |     1 |    26 |     3   (0)|
|* 13 |    HASH JOIN ANTI       |      |     1 |    26 |    15  (14)|
|  14 |     TABLE ACCESS FULL   | T3   |     1 |    13 |     3   (0)|
|  15 |     VIEW                |      |     2 |    26 |    11  (10)|
|  16 |      UNION-ALL          |      |       |       |            |
|* 17 |       HASH JOIN OUTER   |      |     1 |    39 |     6  (17)|
|  18 |        TABLE ACCESS FULL| T1   |     1 |    26 |     2   (0)|
|  19 |        TABLE ACCESS FULL| T2   |     1 |    13 |     3   (0)|
|* 20 |       HASH JOIN ANTI    |      |     1 |    26 |     6  (17)|
|  21 |        TABLE ACCESS FULL| T2   |     1 |    13 |     3   (0)|
|  22 |        TABLE ACCESS FULL| T1   |     1 |    13 |     2   (0)|
---------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("T3"."ID"(+)="T1"."ID")
   6 - access("T2"."ID"(+)="T1"."ID")
   9 - access("T2"."ID"="T1"."ID")
  13 - access("T3"."ID"="T1"."ID")
  17 - access("T2"."ID"(+)="T1"."ID")
  20 - access("T2"."ID"="T1"."ID")

実際、Predicate 情報を除いて、クエリ プランは同じです。

于 2009-01-13T14:47:04.413 に答える
5

あなたは「内部」に興味を示し、次に「意味論」を説明する例を尋ねました。私はセマンティクスに答えています。

これらの表を検討してください。

Table1 : 1, 4, 6
Table2 : 2, 4, 5
Table3 : 3, 5, 6

どちらの例も最初に同じ結合を実行するので、ここで実行します。

FirstResult = T1 FULL JOIN T2 : (T1, T2)
(1, null)
(4, 4)
(6, null)
(null, 2)
(null, 5)

例(A)

FirstResult FULL JOIN T3 ON FirstItem : (T1, T2, T3)

(1, null, null)
(4, 4, null)
(6, null, 6)   <----
(null, 2, null)
(null, 5, null)   <----
(null, null, 3)

例(B)

FirstResult FULL JOIN T3 ON SecondItem : (T1, T2, T3)
(1, null, null)
(4, 4, null)
(6, null, null)   <----
(null, 2, null)
(null, 5, 5)   <----
(null, null, 3)

これは、結合から結果を生成する方法を論理的に示しています。

「内部」には、クエリオプティマイザと呼ばれるものがあります。これは、これらの同じ結果を生成しますが、計算/ioを高速に実行するための実装の選択を行います。これらの選択肢は次のとおりです。

  • 最初にアクセスするテーブル
  • インデックスまたはテーブルスキャンを使用してテーブルを調べます
  • 使用する実装タイプを結合します(ネストされたループ、マージ、ハッシュ)。

また、オプティマイザーがこれらの選択を行い、最適と見なされるものに基づいてこれらの選択を変更するため、結果の順序が変わる可能性があります。結果のデフォルトの順序は、常に「最も簡単なもの」です。デフォルトの順序が必要ない場合は、クエリで順序を指定する必要があります。

オプティマイザーがクエリで何をするかを正確に確認するには(現時点では、考えが変わる可能性があるため)、実行プランを表示する必要があります。

于 2009-01-13T14:58:16.840 に答える
5

EXPLAIN PLAN を使用します。

http://download.oracle.com/docs/cd/B10500_01/server.920/a96533/ex_plan.htm

于 2009-01-13T14:48:06.690 に答える
0

クエリ A を使用すると、テーブル 1 のエントリと、テーブル 3 の対応するエントリを含まないエントリが含まれます (t2 列の場合は null)。

クエリ B uou では、table2 から table3 にしか移動しないため、これらのエントリは取得されません。table2 に対応するエントリがない場合、table2.id は null になり、table3.id と一致しません。

于 2009-01-14T04:59:52.600 に答える