【问题标题】:why oracle optimizer not eliminate this case?为什么 oracle 优化器不消除这种情况?
【发布时间】:2020-02-20 11:04:25
【问题描述】:

我怀疑这个案子,但不清楚原因。

考虑以下 sql:

create table t1(tid int not null, t1 int not null);
create table t2(t2 int not null, tname varchar(30) null);
create unique index i_t2 on t2(t2);
create or replace view v_1 as
select t1.tid,t1.t1,max(t2.tname) as tname
from t1 left join t2
on t1.t1 = t2.t2
group by t1.tid,t1.t1;

然后检查select count(1) from v_1的执行计划,t2被优化器淘汰:

SQL> select count(1) from v_1;


Execution Plan
----------------------------------------------------------
Plan hash value: 3243658773

----------------------------------------------------------------------------------
| Id  | Operation            | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |           |     1 |       |     3  (34)| 00:00:01 |
|   1 |  SORT AGGREGATE      |           |     1 |       |            |          |
|   2 |   VIEW               | VM_NWVW_0 |     1 |       |     3  (34)| 00:00:01 |
|   3 |    HASH GROUP BY     |           |     1 |    26 |     3  (34)| 00:00:01 |
|   4 |     TABLE ACCESS FULL| T1        |     1 |    26 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------------

但如果索引 i_t2 在没有唯一属性的情况下被删除或重新创建,

执行计划中没有淘汰表t2:

SQL> drop index i_t2;

Index dropped.

SQL> select count(1) from v_1;


Execution Plan
----------------------------------------------------------
Plan hash value: 2710188186

-----------------------------------------------------------------------------------
| Id  | Operation             | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |           |     1 |       |     5  (20)| 00:00:01 |
|   1 |  SORT AGGREGATE       |           |     1 |       |            |          |
|   2 |   VIEW                | VM_NWVW_0 |     1 |       |     5  (20)| 00:00:01 |
|   3 |    HASH GROUP BY      |           |     1 |    39 |     5  (20)| 00:00:01 |
|*  4 |     HASH JOIN OUTER   |           |     1 |    39 |     4   (0)| 00:00:01 |
|   5 |      TABLE ACCESS FULL| T1        |     1 |    26 |     2   (0)| 00:00:01 |
|   6 |      TABLE ACCESS FULL| T2        |     1 |    13 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

似乎即使删除了索引,

从 v_1 中选择 count(1) 的结果也等于 select count(1) from (select tid,t1 from t1 group by tid,t1)

为什么优化器在第二种情况下不消除t2?

是否有任何原则或实际数据示例说明这一点? 谢谢:)

【问题讨论】:

    标签: sql oracle optimization


    【解决方案1】:

    这是一种称为联接消除的优化。因为 t2.t2 是唯一的,所以优化器知道从 t1 检索的每一行只能从 t2 检索一行。由于 t2 没有投影,因此无需执行连接。 如果你这样做了

    select tid, t1 from v_1;
    

    您会看到我们不执行连接。但是,如果我们从 t2 投影,则需要连接。

    【讨论】:

    • 谢谢。我很清楚第一种情况。我不清楚第二种情况为什么没有消除 t2。
    • @BobC “在没有唯一属性的情况下重新创建”这就是原因。您说“因为 t2.t2 我们是独一无二的”,但随后 OP 取消了该假设。
    • 在第二种情况下,优化器不知道连接将产生多少行。因此需要完成连接。
    • @BobC 视图有 group by 子句
    • @yaoweijq 由于您的外部查询仅获取分组行的计数,因此即使 t2 索引不唯一,仍然不需要加入 t2 。如果我错了,我相信 Bob 会说为什么它是必要的。但就目前而言,我认为您只是发现了 Oracle 尚未实施的优化。我想这可能是一个错误,但我不会指望任何人承认它。您可能想查看this,因为您的用法有点像子查询。
    猜你喜欢
    • 1970-01-01
    • 2023-02-02
    • 2014-11-15
    • 1970-01-01
    • 1970-01-01
    • 2013-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多