连接列列表中的select方法

问题描述 投票:2回答:1

这是一个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可以在这个计划背后有不同的连接方法,还是总是相同的?

非常感谢你!

oracle oracle11g sql-execution-plan
1个回答
3
投票

首先,您应该使用更新的技术来检查执行计划,例如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行中,你看到恒星= 100,意味着FULL SCAN被启动了100次。

注意 - 执行计划可能会根据表统计信息,优化程序设置或Oracle版本而更改(例如,Oracle可以重写子查询并使用连接)。

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

© www.soinside.com 2019 - 2024. All rights reserved.