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



我得到了一个非常简单的查询,当在同一硬件中运行Spark SQL和Presto(3小时vs 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的正确语义。

然而,左反联接谓词的OR导致Left AntiJoin唯一可行的物理联接策略是BroadcastNestedLoopJoin。对于当前阶段,我可以将NOT IN重写为NOT EXISTS来解决这个问题。在NOT EXISTS的查询计划中,我可以看到连接谓词是Left AntiJoin(test1=test2),这为NOT EXISTS带来了更好的物理连接运算符(5分钟后完成(。

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

所以我检查了Presto的查询计划,它并没有真正提供Left AntiJoin,但它使用了带有FilterPredicate = not (expr)SemiJoin。Presto的查询计划没有像Spark那样提供太多信息。

所以我的问题更像是:

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

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

Presto使用";复制null和任何行";复制模式,加上散列分区,这使它能够在IN两侧存在NULL的情况下正确处理IN,而不会倒退到广播,也不会使执行成为单线程或单节点。运行时性能成本实际上与根本不存在NULL值的情况相同。

如果你想了解更多关于Presto内部的信息,请加入Trino Community Slack上的#dev频道。

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

相关内容

  • 没有找到相关文章

最新更新