在 Oracle 中,这是带有过滤器的交叉连接还是内部连接?

Posted

技术标签:

【中文标题】在 Oracle 中,这是带有过滤器的交叉连接还是内部连接?【英文标题】:In Oracle, is this a cross join with a filter or a inner join? 【发布时间】:2022-01-12 22:11:31 【问题描述】:

我在一些遗留的 sql 代码中遇到了这个问题,我想知道它是如何“在幕后”工作的。在下面的示例中,sql 引擎是将其视为带有过滤器的交叉连接还是“LIKE”关键字上的常规内部连接?

Select 
        t1.col1,
        t2.col2
From
        table1 t1,
        table2 t2
Where t1.approved           IS NULL
        AND UPPER(NVL(t1.team, '%'))            LIKE UPPER(NVL(t2.TEAM, '%'))
        ;

【问题讨论】:

是的,那是 1989 年的旧连接语法。它被称为“逗号分隔表”,现在非常不鼓励使用。 INNER JOIN 是笛卡尔积的子集,其中输出仅包含满足连接谓词的那些行。这种连接的正式定义与笛卡尔积上的过滤器相同:select * from A join B on P(a,b) = [(a,b) : a ∈ A, b ∈ B, P(a,b) = 1]explain plan 可以看到幕后发生的事情 我想更大的问题是为什么这不是 Oracle 中的内部联接? Select t1.col1, t2.col2 From table1 t1, table2 t2 Where t1.approved IS NULL AND UPPER('%') LIKE UPPER('%') ;它们导致不同的解释计划。 这不是内部联接,因为您没有引用两个表中的列。但是如果你在表名之间显式地放置一个inner join 文本,由于同样的原因和上面提到的定义,它不会变成一个内连接。这只是一个约定,您也可以通过在右表的列上应用任何比较来将显式 left join 转换为 inner 【参考方案1】:

交叉连接是完整的笛卡尔积。它导致两个表之间所有可能的组合。 如果过滤器引用两个表的列,则与过滤器的交叉连接可以是内部连接。 您的 SQL 肯定是内连接,因为它不是笛卡尔积并引用两个表的列。

您可以使用各种形式的内连接,例如

where substr(t1.col1, 1, 2) = t2.col2
where t1.col1 between t2.col1 and t2.col2

【讨论】:

【参考方案2】:

实际上是INNER JOIN:

SELECT t1.col1,
       t2.col2
FROM   table1 t1
       INNER JOIN table2 t2
       ON (   NVL(UPPER(t1.team), '%') LIKE UPPER(t2.team)
           OR t2.team IS NULL)
WHERE  t1.approved IS NULL;

【讨论】:

【参考方案3】:

如果您想了解它是如何“在幕后”工作的,请运行一个解释计划

Oracle 优化器在实际解析查询时会将查询重写为不同的形式。例如,我刚刚运行了一个测试,所有这 3 个查询:

select *
from table1 t1, table2 t2
where nvl(t1.team,'%') like nvl(t2.team, '%');

select *
from table1 t1
inner join table2 t2
on nvl(t1.team,'%') like nvl(t2.team, '%');

select *
from table1 t1
cross join table2 t2
where nvl(t1.team,'%') like nvl(t2.team, '%');

在我的环境中被翻译成同样的解释计划:

SELECT STATEMENT  FIRST_ROWS Cost: 13  Bytes: 437,265  Cardinality: 1,845       
3 NESTED LOOPS  Cost: 13  Bytes: 437,265  Cardinality: 1,845    
    1 TABLE ACCESS FULL TABLE MYSCHEMA.TABLE1 Cost: 2  Bytes: 36,162  Cardinality: 369  
    2 TABLE ACCESS FULL TABLE MYSCHEMA.TABLE2 Cost: 11  Bytes: 256,455  Cardinality: 1,845  

这意味着就 Oracle 而言,考虑到特定的表、行数和可用的统计信息,这 3 个查询是相同的。在大多数情况下,它们在逻辑上是等价的。

但是,这是一个简单的查询。如果您开始添加更多 WHERE 条件,或者表中的数据结构不同,或者如果您有索引,优化器可能会选择不同的计划,并且查询可能会执行不同的操作。

【讨论】:

以上是关于在 Oracle 中,这是带有过滤器的交叉连接还是内部连接?的主要内容,如果未能解决你的问题,请参考以下文章

带有Sum的Oracle SQL交叉表

[Oracle]多表连接技术-交叉连接非等值连接等值连接外连接

oracle连接总结(内连接外连接自然连接,交叉连接,自连接)

选择与表值函数连接中的 Oracle 标量函数

Oracle XMLtable 提供交叉连接的数据

带有左连接的 Oracle 更新