我需要有关 Oracle 执行计划的解释和建议。
我的 Oracle 数据库中有 3 个表:
id是每个表中的主键。
表 t 有 13 000 000 行,t1 有 4 000 000 行,t2 有 1 000 000 行。
以下查询在执行计划中显示“哈希连接”:
select
t.*
from t
left join t1 on t1.id = t.t1_id
但是使用表 t2 而不是 t1 的相同查询在执行计划中不会显示“哈希联接”(表 t 只有“表访问”):
select
t.*
from t
left join t2 on t2.id = t.t2_id
在我看来,两个查询都不应该在执行计划中显示“哈希连接”,因为由于主键,左连接操作无法更改结果集中的行数,并且我们不从中选择任何字段select 语句中的 t1 和 t2。对于表 t2,效果很好。为什么表t1的执行计划不同?
为了更清楚地说明,我需要这样的行为,因为在我的实际情况中,有数十个不同的“左连接”,并且我的 BI 的不同用户将选择不同的字段集。但没有人会选择所有领域。我希望 Oracle 仅对那些选择了字段的表实施左联接。如果 Oracle 将实现所有左连接,那么查询将会太长。
t
中的每个匹配行,从
t2
增加一行,无论您是要求查看任何 t2
列还是不是。因此,从语义上来说,Oracle 必须执行连接。它唯一可以跳过连接的时候是当它知道外部连接将找到 0 个匹配项时(例如,如果您使用带有错误值的 AND
逻辑,或者如果您键入 NULL
或类似的东西)。这里的情况并非如此。它可能会找到匹配项,因此必须尝试,因为这将确定返回的行数。对于连接方法,Oracle 将根据其成本计算方法和对数据的假设在 (1) 嵌套循环、(2) 排序合并连接、(3) 哈希连接之间进行选择。您的查询没有应用谓词,并且驱动结果集很大 - 难怪它更喜欢哈希连接。这样做是正确的。嵌套循环(假设您在 t1.t1_id
上有一个索引)将需要 1300 万次索引查找,如果找到匹配,则从表段中获取另外 1300 万个单块。这比进行全表扫描并在内存中构建适度大小的哈希表的几千个多块读取(特别是如果它们走直接路径)要多得多的工作。
至于为什么加入t2
时会看到不同的东西,我们得看看执行计划。请发布这两个示例。