Я получил очень простой запрос, который показывает значительную разницу в производительности при работе на Spark SQL и Presto (3 часа против 3 минут) на одном оборудовании.
SELECT field
FROM test1
WHERE field NOT IN (SELECT field FROM test2)
После некоторого исследования плана запросов я выяснил, что причина в том, как Spark SQL работает с подзапросом предиката NOT IN
. Чтобы правильно обработать NULL из NOT IN, Spark SQL переводит предикат NOT IN
как Left AntiJoin( (test1=test2) OR isNULL(test1=test2))
.
В Spark SQL вводится OR isNULL(test1=test2)
для обеспечения правильной семантики NOT IN
.
Однако, OR
предиката соединения Left AntiJoin приводит к единственно возможной стратегии физического соединения для Left AntiJoin
- BroadcastNestedLoopJoin
. Для текущей стадии я мог бы переписать NOT IN в NOT EXISTS, чтобы обойти эту проблему. В плане запроса NOT EXISTS я мог видеть предикат соединения Left AntiJoin(test1=test2)
, который заставляет лучший оператор физического соединения для NOT EXISTS (5 минут до конца).
Пока что мне повезло, так как мой набор данныхв настоящее время не имеет атрибутов NULL
, но может иметь в будущем, и семантика NOT IN - это то, что я действительно хочу.
Поэтому я проверяю план запросов Presto, он на самом деле не предоставляет Left AntiJoin
но он использует SemiJoin
с FilterPredicate = not (expr)
. План запросов Presto не предоставляет слишком много информации, такой как Spark.
Так что мой вопрос больше похож на:
Могу ли я предположить, что в Presto есть лучший оператор физического соединения для обработки операции NOT IN
? В отличие от Spark SQL, он не использует перезапись предикатов соединения isnull(op1 = op2)
для обеспечения правильной семантики NOT IN на уровне логического плана.