谓词中带有“或”的慢速连接行为

smw*_*ody 5 oracle join oracle-10g plsql

我面临着一种我无法理解和克服的情况。

简而言之,我们有左连接查询,如:

select from a 
left join b on a.key1=b.key1 or a.key1=b.key2
Run Code Online (Sandbox Code Playgroud)

这工作非常缓慢,同时两者分开:

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

select from a 
left join b on a.key1=b.key2
Run Code Online (Sandbox Code Playgroud)

工作非常快。

b.key1 有正常索引

b.key2 有正常索引

我无法理解这种行为的原因?我的连接策略或索引使用中是否缺少一些非常基本的东西?

在这里,我们有详细的计划:

无或(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)
Run Code Online (Sandbox Code Playgroud)

与或:

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")
Run Code Online (Sandbox Code Playgroud)

为什么or在谓词中使用 using给出嵌套循环而没有使用索引?是否可以强制使用索引?

更新: “没有或”的错误附加错误计划。已修复

小智 6

OR 速度较慢,因为您不再可以执行索引查找,但会有效地强制数据库引擎查找索引树中的每个叶节点。使用单个参数(无 OR),引擎可以通过索引向下查找相关叶节点,但是当您向它询问 OR 时,它会扫描叶节点的整个范围。

如果性能太慢而无法容忍,请按照注释建议进行操作,并尝试 UNION(无重复值)或 UNION ALL(允许重复值),甚至单独两个单独的查询,然后在代码中将结果连接在一起层接收结果。