Oracle 的优化器是不是考虑子查询的基础列?
Posted
技术标签:
【中文标题】Oracle 的优化器是不是考虑子查询的基础列?【英文标题】:Does Oracle's Optimizer Take into Consideration a Subquery's Underlying Columns?Oracle 的优化器是否考虑子查询的基础列? 【发布时间】:2019-01-05 03:26:07 【问题描述】:假设您有这样的查询:
with subselect as (
select foo_id
from foo
)
select bar_id
from bar
join subselect on foo_id = bar_id
where foo_id = 1000
假设您在 foo_id 上有一个索引。 Oracle 的数据库是否足够智能,可以在查询中使用“where foo_id = 1000”行的索引? OR 由于 foo_id 被包裹在子查询中,Oracle 是否会丢失与该列相关的索引信息?
【问题讨论】:
计划说明了什么? 查询优化器会考虑查询中的所有列。是什么让你觉得不是?您可以通过检查查询计划来验证这一点。 有点不可能肯定地回答(也许优化器会进行表扫描,因为最大的表中只有 5 行,使用索引不值得努力)但没有理由假设,因为您使用优化器太笨而无法考虑它们的子查询。 优化器分析查询的每一位以确定一个计划,在较新的版本中,如果它发现它做出了一个不太理想的决定,它甚至会在执行过程中更改计划。子查询并不特殊......它们基本上被视为任何其他“常规”查询。使用索引并不总是让事情变得更好。查看执行计划以了解如何处理您的子查询 【参考方案1】:执行一个简单的测试:
create table foo as
select t.object_id as foo_id, t.* from all_objects t;
create table bar as
select t.object_id as bar_id, t.* from all_objects t;
create index foo_id_ix on foo(foo_id);
exec dbms_stats.GATHER_TABLE_STATS(ownname=>user, tabname=>'FOO', method_opt=>'FOR ALL INDEXED COLUMNS' );
explain plan for
with subselect as (
select foo_id
from foo
)
select bar_id
from bar
join subselect on foo_id = bar_id
where foo_id = 1000;
select * from table( DBMS_XPLAN.DISPLAY );
最后一次查询的结果是:
Plan hash value: 445248211
----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 366 (1)| 00:00:01 |
| 1 | MERGE JOIN CARTESIAN| | 1 | 10 | 366 (1)| 00:00:01 |
|* 2 | TABLE ACCESS FULL | BAR | 1 | 5 | 365 (1)| 00:00:01 |
| 3 | BUFFER SORT | | 1 | 5 | 1 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | FOO_ID_IX | 1 | 5 | 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("BAR_ID"=1000)
4 - access("FOO_ID"=1000)
在上面的示例中,Oracle 使用|* 4 | INDEX RANGE SCAN
使用索引:FOO_ID_IX
过滤4 - access("FOO_ID"=1000)
所以答案是:是的,Oracle 的数据库足够智能,可以使用查询中的索引来查找“where foo_id = 1000”这一行
【讨论】:
以上是关于Oracle 的优化器是不是考虑子查询的基础列?的主要内容,如果未能解决你的问题,请参考以下文章