在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
这两个都提供谓词下推优化吗?
谢谢
答案 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。