web-dev-qa-db-ja.com

述語に「or」を使用した遅い結合動作

私は理解できず、克服できない状況に直面しています。

つまり、次のような左結合クエリがあります。

select from a 
left join b on a.key1=b.key1 or a.key1=b.key2

これは非常にゆっくりと動作しますが、同時に両方とも別々に動作します。

select from a 
left join b on a.key1=b.key1

select from a 
left join b on a.key1=b.key2

非常に速く動作します。

b.key1には通常のインデックスがあります

b.key2には通常のインデックスがあります

そのような振る舞いの理由がわかりませんか?結合戦略またはインデックスの使用法で非常に基本的なものが欠けていますか?

ここでは、詳細な計画について説明します。

WITHOUT OR(TOP_USTR_ADMIN_IP-ustrip列のインデックス名):

SQL> explain plan for
SELECT * FROM top.macs_constraint mc 
LEFT JOIN top.top_ustr tu ON  tu.ustrip = mc.IP;

Explained.

SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

   Plan hash value: 349751289

--------------------------------------------------------------------------------------------
| Id  | Operation              | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |                   |     1 |    22 |  1296   (1)| 00:00:16 |
|   1 |  SORT AGGREGATE        |                   |     1 |    22 |            |              |
|*  2 |   HASH JOIN RIGHT OUTER|                   |   981K|    20M|  1296   (1)| 00:00:16 |
|*  3 |    INDEX FAST FULL SCAN| TOP_USTR_ADMIN_IP | 23187 |   181K|    62   (0)| 00:00:01 |
|   4 |    TABLE ACCESS FULL   | MACS_CONSTRAINT   |   629K|  8601K|  1231   (1)| 00:00:15 |
--------------------------------------------------------------------------------------------

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------

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

   2 - access("TU"."USTRIP"(+)="MC"."IP")
   3 - filter("TU"."USTRIP"(+) IS NOT NULL)

または:

explain plan for
SELECT count(*) FROM top.macs_constraint mc 
LEFT JOIN top.top_ustr tu ON (tu.ustrip = mc.IP or tu.skladIP = mc.IP);  

Explained.

SQL> SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY());

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 2704565128

----------------------------------------------------------------------------------------
| Id  | Operation            | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                 |     1 |    14 |   322M  (1)|999:59:59 |
|   1 |  SORT AGGREGATE      |                 |     1 |    14 |            |            |
|   2 |   NESTED LOOPS OUTER |                 |  1887K|    25M|   322M  (1)|999:59:59 |
|   3 |    TABLE ACCESS FULL | MACS_CONSTRAINT |   629K|  8601K|  1231   (1)| 00:00:15 |
|   4 |    VIEW              |                 |     3 |       |   513   (1)| 00:00:07 |
|*  5 |     TABLE ACCESS FULL| TOP_USTR        |     3 |    72 |   513   (1)| 00:00:07 |

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------

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

   5 - filter("TU"."SKLADIP" IS NOT NULL AND "TU"."SKLADIP"="MC"."IP" OR  
              "TU"."USTRIP" IS NOT NULL AND "TU"."USTRIP"="MC"."IP")

述語でorを使用すると、ループがネストされ、インデックスが使用されないのはなぜですか?インデックスの使用を強制することは可能ですか?

更新:「なし」または「。」の誤った計画の添付ミス

4
smwoody

ORはインデックスシークを実行できなくなるため遅くなりますが、データベースエンジンはインデックスツリーの各リーフノードを効率的に検索します。単一のパラメーター(ORなし)を使用すると、エンジンは関連するリーフノードまでインデックスをシークできますが、ORを要求すると、リーフノードの全範囲をスキャンします。

パフォーマンスが遅すぎて許容できない場合は、コメントが示唆するようにして、UNION(重複値なし)またはUNION ALL(重複値を許可)、または2つの個別のクエリを独自に実行し、結果をコードで結合します。結果を受け取る層。

3
Allan S. Hansen