Oracle

謂詞中帶有“或”的慢連接行為

  • October 22, 2013

我面臨著我無法理解和克服的情況。

簡而言之,我們有左連接查詢,例如:

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在謂詞中使用會給出嵌套循環並且沒有索引使用?是否可以強制使用索引?

更新: “沒有或”的錯誤計劃。已修復

OR 速度較慢,因為您不再可以執行索引查找,但有效地強制數據庫引擎查看索引樹中的每個葉節點。使用單個參數(無 OR),引擎可以通過索引向下查找相關葉節點,但是當您向它詢問 OR 時,它會掃描整個葉節點範圍。

如果性能太慢而無法容忍,請按照評論的建議進行操作並嘗試 UNION(無重複值)或 UNION ALL(允許重複值),甚至兩個單獨的查詢,然後在程式碼中將結果連接在一起層接收結果。

引用自:https://dba.stackexchange.com/questions/51914