左加入蜂巢,在扫描前不通过过滤器

问题描述

我使用的是 Hive 2.3.5 Spark 2.3.3 版本

当我在 hive 上运行以下查询时,它失败了...说试图扫描太多分区。

select t1.A,t2.B 
   from t1 left join t2 on t1.x = t2.x
    where t1.x = 'abc'

与我运行时相比,它工作正常:

 select t1.A,t2.B 
 from t1 left join t2 on t1.x = t2.x
    where t1.x = 'abc'
    and t2.x = 'abc'

当我已经在 t1.x = t2.x 上进行连接时,为什么我需要再次在表 t2 上传递显式过滤器 (t2.x='abc') 其中 t1.x = 'abc'?

正常连接无需额外过滤器即可正常工作,但不允许连接

解决方法

优化器并不总是可以下推谓词,因为它不够智能。并且 WHERE 最有可能在 join 之后被应用,导致扫描太多行。 可能 PPD 与 INNER JOIN 一起工作得很好。 EXPLAIN 计划可能会提供有关计划的更多信息。

但除此之外,还有一个问题。

你是说 INNER join 工作正常...看:

您的两个查询完全不同。第一个是LEFT JOIN。如果 t2 不包含 t2.x = 'abc' 的行,它将返回来自 t1 的行。

第二个有不同的行为,它是一个 INNER JOIN,实际上是因为 where t2.x = 'abc' 中的这个谓词不允许 NULL,过滤掉没有与 t2 连接的记录。检查它,您只选择加入的记录 = INNER JOIN。如果表不包含 t2.x = 'abc' 的行,则第二个查询将不返回任何行。

尝试向 ON 而不是 WHERE 添加一个连接条件,这看起来更像 LEFT JOIN

select t1.A,t2.B 
 from t1 left join t2 on t1.x = t2.x and t2.x='abc' 
    where t1.x = 'abc'

我并不是说这将解决扫描过多分区的问题,我只是说这将是真正的左联接,而不是内部联接,并且谓词将在联接之前应用于 t2。

另一种方法是在加入前在子查询中使用过滤。

   select t1.A,t2.B 
     from (select * from t1 where t1.x = 'abc') t1 
         left join (select * from t2 where t2.x = 'abc') t2 
                  on t1.x = t2.x