列列表中 select 的连接方法
join method of select in column list
这是一个 11g 的问题,但我想这是版本无关的问题。
我有这个简单的select:
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_A
和 TAB_B
的散列连接结果?是否针对散列连接的每个结果在嵌套循环中访问一次?它是以 TAB_C
作为驱动 table 的散列连接吗?排序合并?有什么完全不同的吗? 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
的信息。您在 Predicate Information 中看到第 1 filter("C"."ID"=:B1)
.
换句话说,您将完整扫描 table 以查找 table 中 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 次。
警告 - 执行计划可能会根据 table 统计信息、优化器设置或 Oracle 版本(例如 Oracle 可以 rewrite 子查询并使用连接)。
这只是 11.2 上带有虚拟 tables 的示例。
但是您应该了解如何观察 Oracle 的行为并决定是否需要额外的索引。
这是一个 11g 的问题,但我想这是版本无关的问题。
我有这个简单的select:
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_A
和 TAB_B
的散列连接结果?是否针对散列连接的每个结果在嵌套循环中访问一次?它是以 TAB_C
作为驱动 table 的散列连接吗?排序合并?有什么完全不同的吗? 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
的信息。您在 Predicate Information 中看到第 1 filter("C"."ID"=:B1)
.
换句话说,您将完整扫描 table 以查找 table 中 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 次。
警告 - 执行计划可能会根据 table 统计信息、优化器设置或 Oracle 版本(例如 Oracle 可以 rewrite 子查询并使用连接)。
这只是 11.2 上带有虚拟 tables 的示例。 但是您应该了解如何观察 Oracle 的行为并决定是否需要额外的索引。