谓词下推与On子句

时间:2019-04-28 18:32:31

标签: join hive on-clause

在Hive中执行联接,然后使用where子句过滤输出时,Hive编译器将尝试在联接表之前过滤数据。这称为谓词下推(http://allabouthadoop.net/what-is-predicate-pushdown-in-hive/

例如:

SELECT * FROM a JOIN b ON a.some_id=b.some_other_id WHERE a.some_name=6

如果启用了下推谓词(hive.optimize.ppd),则将在执行联接之前过滤表a中具有some_name = 6的行。

但是,我最近还了解到,在将数据与另一个表(https://vinaynotes.wordpress.com/2015/10/01/hive-tips-joins-occur-before-where-clause/)联接之前,还有另一种从表中过滤数据的方法。

一个人可以在ON子句中提供条件,并且在执行连接之前将过滤表a

例如:

SELECT * FROM a JOIN b  ON a.some_id=b.some_other_id AND a.some_name=6

这两个都提供谓词下推优化吗?

谢谢

1 个答案:

答案 0 :(得分:1)

两者均有效,并且在INNER JOIN和PPD的情况下都将相同。但是,在使用外部联接的情况下,这些方法的工作原理有所不同

ON加入条件在加入之前起作用。

加入后在哪里应用。

Optimizer决定谓词下推是否适用,并且可能起作用,但是对于LEFT JOIN(例如,在右表中带有WHERE过滤器的情况), WHERE过滤器

SELECT * FROM a 
             LEFT JOIN b ON a.some_id=b.some_other_id 
 WHERE b.some_name=6 --Right table filter

将限制NULL,并且LEFT JOIN将转换为INNER JOIN,因为如果b.some_name = 6,则不能为NULL。

PPD不会更改此行为。

如果您在右表中添加允许NULL的其他OR条件,仍然可以使用WHERE过滤器进行LEFT JOIN:

SELECT * FROM a 
             LEFT JOIN b ON a.some_id=b.some_other_id 
 WHERE b.some_name=6 OR b.some_other_id IS NULL --allow not joined records

如果您有多个具有许多此类过滤条件的联接,则这样的逻辑将使您的查询难以理解并且会出错。

具有ON过滤器的LEFT JOIN不需要附加的OR条件,因为它在连接之前过滤了正确的表,此查询按预期工作并且易于理解:

SELECT * FROM a 
             LEFT JOIN b ON a.some_id=b.some_other_id and b.some_name=6

PPD仍然适用于ON过滤器,并且如果表b是ORC,则PPD会将谓词推至ORC读取器的最低级别,并将使用内置的ORC索引在三个级别上进行过滤:行,条带和文件。

有关同一主题的更多信息和一些测试:https://stackoverflow.com/a/46843832/2700344

因此,无论是PPD还是非PPD,最好使用具有ON条件和ON过滤的显式ANSI语法,以使查询尽可能简单,并避免无意间转换为INNER JOIN。