不在Presto v.s Spark SQL的实现中

我得到了一个非常简单的查询,该查询在同一硬件上运行Spark SQL和Presto时(3小时v.s 3分钟)显示出显着的性能差异。

SELECT field 
FROM test1 
WHERE field NOT IN (SELECT field FROM test2)

对查询计划进行了一些研究之后,我发现原因是Spark SQL如何处理NOT IN谓词子查询。 为了正确处理NOT IN的NULL,Spark SQL将NOT IN谓词转换为Left AntiJoin( (test1=test2) OR isnULL(test1=test2))

Spark SQL引入了OR isnULL(test1=test2)以确保NOT IN的正确语义。

但是,Left AntiJoin连接谓词的OR导致Left AntiJoin唯一可行的物理连接策略是BroadcastnestedLoopJoin。在当前阶段,我可以将NOT IN改写为NOT EXISTS来解决此问题。在NOT EXISTS的查询计划中,我可以看到join谓词为Left AntiJoin(test1=test2),这为NOT EXISTS(需要5分钟完成)带来了更好的物理联接运算符。

到目前为止,我很幸运,因为我的数据集目前没有任何NULL属性,但是将来可能会拥有,而NOT IN的语义正是我真正想要的。

因此,我检查了Presto的查询计划,它实际上没有提供Left AntiJoin,但它使用SemiJoinFilterPredicate = not (expr)。 Presto的查询计划没有提供太多信息,例如Spark。

所以我的问题更像是:

我可以认为Presto具有更好的物理联接运算符来处理NOT IN操作吗?与Spark SQL不同,它不依赖于连接谓词isnull(op1 = op2)的重写来确保逻辑计划级别中NOT IN的正确语义。

qq376055355 回答:不在Presto v.s Spark SQL的实现中

我实际上是在Presto中对半联接(NULL谓词)实施IN处理的人。

Presto除了使用散列分区¹之外,还使用“复制空值和任何行”复制模式,这使它可以在{{1}的任一侧存在IN的情况下正确处理NULL }},而不会退回到广播,也不会使执行成为单线程或单节点。运行时性能成本实际上与根本没有IN值的情况相同。

如果您想了解有关Presto内部的更多信息,请在Presto Community Slack上加入NULL频道。

¹)准确地说,半联接是散列分区或广播的,具体取决于基于成本的决策或配置。

本文链接:https://www.f2er.com/3150050.html

大家都在问