oracle - 列列表中select的join方法

标签 oracle oracle11g sql-execution-plan

这是一个 11g 问题,但我想这与版本无关。

我有这个简单的选择:

create table tab_a (id number);
create table tab_b (id number);
create table tab_c (id number);

select 
    a.id,b.id,(select c.id from tab_c c where c.id = a.id) 
from 
    tab_a a join tab_b b on a.id = b.id;

这给了我这样一个计划:

SELECT LPAD(' ',depth)||OPERATION||'_'||OPTIONS||' '||OBJECT_NAME plan
FROM v$sql_plan
WHERE plan_hash_value = 2530031923
order by id;
SELECT STATEMENT_ 
 TABLE ACCESS_FULL TAB_C
 HASH JOIN_ 
  TABLE ACCESS_FULL TAB_A
  TABLE ACCESS_FULL TAB_B

我现在的问题是:TAB_C 如何连接到 TAB_ATAB_B 的哈希连接结果?对于哈希连接的每个结果,是否在嵌套循环中访问一次?它是一个以 TAB_C 作为驱动表的哈希连接吗?排序合并?有什么完全不同的吗?此计划背后的 TAB_C 是否可以有不同的连接方法,还是始终相同?

非常感谢!

最佳答案

首先,您应该使用更新的技术来检查执行计划,例如DBMS_XPLAN.DISPLAY`

EXPLAIN PLAN  SET STATEMENT_ID = 'sqlx' into   plan_table  FOR
select 
    a.id,b.id,(select c.id from tab_c c where c.id = a.id) 
from 
    tab_a a join tab_b b on a.id = b.id;


SELECT * FROM table(DBMS_XPLAN.DISPLAY('plan_table', 'sqlx','ALL'));    

    ----------------------------------------------------------------------------
| Id  | Operation          | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |   100 |  2600 |     7  (15)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL | TAB_C |     1 |    13 |     3   (0)| 00:00:01 |
|*  2 |  HASH JOIN         |       |   100 |  2600 |     7  (15)| 00:00:01 |
|   3 |   TABLE ACCESS FULL| TAB_A |   100 |  1300 |     3   (0)| 00:00:01 |
|   4 |   TABLE ACCESS FULL| TAB_B |   100 |  1300 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------

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

   1 - filter("C"."ID"=:B1)
   2 - access("A"."ID"="B"."ID")

这为您提供了如何访问TAB_C的信息。您可以在第 1 行的谓词信息中看到 filter("C"."ID"=:B1)

换句话说,您将全面扫描表 A 和 B 之间连接的每个 ID。这当然是不希望的。

如果您不相信这个简单的操作,请运行查询并收集计划统计信息

select /*+ gather_plan_statistics */
    a.id,b.id,(select c.id from tab_c c where c.id = a.id) 
from 
    tab_a a join tab_b b on a.id = b.id;  

---
select * from table(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST')); 

SQL_ID  4m4a1cp4gyjkv, child number 0
-------------------------------------
select /*+ gather_plan_statistics */     a.id,b.id,(select c.id from 
tab_c c where c.id = a.id)  from      tab_a a join tab_b b on a.id = 
b.id

Plan hash value: 2606630813

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name  | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |       |      1 |        |    100 |00:00:00.01 |      15 |       |       |          |
|*  1 |  TABLE ACCESS FULL | TAB_C |    100 |      1 |    100 |00:00:00.01 |     700 |       |       |          |
|*  2 |  HASH JOIN         |       |      1 |    100 |    100 |00:00:00.01 |      15 |  1517K|  1517K| 1256K (0)|
|   3 |   TABLE ACCESS FULL| TAB_A |      1 |    100 |    100 |00:00:00.01 |       7 |       |       |          |
|   4 |   TABLE ACCESS FULL| TAB_B |      1 |    100 |    100 |00:00:00.01 |       8 |       |       |          |
-----------------------------------------------------------------------------------------------------------------

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

   1 - filter("C"."ID"=:B1)
   2 - access("A"."ID"="B"."ID")

在第 1 行中,您可以看到starts = 100,这意味着FULL SCAN 启动了100 次。

警告 - 执行计划可能会根据表统计信息、优化器设置或 Oracle 版本而变化(例如,Oracle 可以重写子查询并使用联接)。

这只是 11.2 上虚拟表的示例。 但您应该了解如何观察 Oracle 的行为并决定是否需要额外的索引。

关于oracle - 列列表中select的join方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55235946/

相关文章:

sql - Oracle ROUND 函数返回错误值

Oracle EXECUTE IMMEDIATE 更改解释查询计划

java - 强制 Oracle JDBC 在每个连接上使用代理

找不到 Python 模块 "cx_Oracle"模块

sql - 数据库链接连接超时

vb.net - 将 Blob 图像导入 ms Access 报表时出现异常

SQL 错误 : ORA-02291: integrity constraint

oracle - 如何将新添加的列的值添加到 Oracle 11g 中的所有现有行

mysql - 更好的 MySQL 查询性能

oracle - 不同的参数大小导致查询计划缓存效率低下