如果我没有读取联接表中的任何列,Oracle 优化器仍会计划联接吗?

Mih*_*hai 6 oracle optimization

假设我有以下观点:

CREATE VIEW dummy AS
SELECT a.some_column, b.other_column
FROM a LEFT JOIN b USING (key_column);
Run Code Online (Sandbox Code Playgroud)

当我执行 a 时SELECT some_column FROM dummy,有没有办法指示优化器将查询重写为SELECT some_column FROM a并跳过连接?如何?

ype*_*eᵀᴹ 9

决定性因素是 上是否存在唯一约束/索引b (key_column)

如果没有唯一约束,则 中可能存在重复值b.key_column,因此优化器必须始终制定从表中读取的计划(如果该列上有索引,则必须制定一个索引)。

如果相反,存在唯一约束,则查询相当于您的重写(SELECT some_column FROM a;问题是 Oracle 是否在其优化器的查询转换套件中实现了此技巧。

事实上,它已在 10gR2 版本中实现,并在 11gR1 中得到进一步增强,它被称为Table Elimination。更多信息可以在 oracle 博客文章中找到:为什么我的查询中的某些表从计划中丢失?这篇文章解释了 11gR1 增强包括这种特殊情况(外连接表消除),外连接到具有唯一约束的表,并且有一个几乎与您相同的示例。

我们也可以通过一个简单的比较来检查。请注意SQLfiddle 中两种情况之间执行计划的差异

-- Case 1
create table b
( key_column int                      -- no unique constraint
, other_column int
) ;
insert into b values (1, 1) ;
insert into b values (2, 2) ;
insert into b values (3, 3) ;
insert into b values (4, 4) ;
insert into b values (1, 2) ;      -- some duplicate values
insert into b values (1, 3) ;      -- in key_column

-- Case 2
create table bb
( key_column int primary key       -- has a unique constraint
, other_column int
) ;

insert into bb values (1, 1) ;
insert into bb values (2, 2) ;
insert into bb values (3, 3) ;
insert into bb values (4, 4) ;

-- Both cases
create table a
( some_column int primary key,
  key_column int 
) ;

insert into a values (101, 1) ;
insert into a values (202, 2) ;
Run Code Online (Sandbox Code Playgroud)

我们为这两种情况创建视图:

CREATE VIEW dummy AS
SELECT a.some_column, b.other_column
FROM a LEFT JOIN b USING (key_column);

CREATE VIEW dummy_bb AS
SELECT a.some_column, bb.other_column
FROM a LEFT JOIN bb USING (key_column);
Run Code Online (Sandbox Code Playgroud)

现在运行查询,使用视图和使用表 - 除了连接到表bbb其中表不同的地方相同,只有第二个对 有唯一约束key_column

SELECT some_column FROM dummy ;

SELECT some_column FROM (
    SELECT a.some_column, b.other_column
    FROM a LEFT JOIN b USING (key_column)
);
Run Code Online (Sandbox Code Playgroud)

我们看到,在案例 1 中访问表,b而在案例 2 中则没有(使用未公开的转换)。