谓词下推 vs On 子句

Posted

技术标签:

【中文标题】谓词下推 vs On 子句【英文标题】:Predicate Pushdown vs On Clause 【发布时间】:2019-09-17 11:41:53 【问题描述】:

当在 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子句中提供条件,在join之前会过滤表a

例如:

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

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

谢谢

【问题讨论】:

【参考方案1】:

两者都是有效的,在 INNER JOIN 和 PPD 的情况下,两者的工作方式相同。但是在 OUTER JOINS 的情况下,这些方法的工作方式不同

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

WHERE 在加入后应用。

优化器决定谓词下推是否适用,它可能会起作用,但在 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 不会改变这种行为。

如果您添加额外的 OR 条件允许在右表中使用 NULL,您仍然可以使用 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://***.com/a/46843832/2700344

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

【讨论】:

以上是关于谓词下推 vs On 子句的主要内容,如果未能解决你的问题,请参考以下文章

谓词下推

SQL 优化技术系列: 谓词下推

SQLServer 列存储索引的性能问题:“Where OR”将影响谓词下推

hive sql 优化

BIGQUERY:连接谓词中的表不受支持的子查询

Linq In 子句和谓词构建