EXISTS 和 IN 的 Spark 替换

Spark replacement for EXISTS and IN

我正在尝试 运行 使用 EXIST 子句的查询:

select <...>    
  from A, B, C
where
  A.FK_1 = B.PK and
  A.FK_2 = C.PK and
  exists (select A.ID from <subquery 1>) or 
  exists (select A.ID from <subquery 2>) 

很遗憾,这似乎不受支持。我还尝试用 IN 子句替换 EXISTS 子句:

select <...>    
  from A, B, C
where
  A.FK_1 = B.PK and
  A.FK_2 = C.PK and
  A.ID in (select ID from ...) or
  A.ID in (select ID from ...)

不幸的是,IN 子句似乎也不受支持。

关于如何编写 SQL 查询以达到预期结果的任何想法?原则上我可以将 WHERE 子句建模为另一个 JOIN 并将第二个 OR 子句建模为 UNION 但它看起来超级笨拙..

编辑:列出许多可能的解决方案。

解决方案 1

select <...>    
  from A, B, C
       (select ID from ...) as exist_clause_1,
       (select ID from ...) as exist_clause_2,
where
  A.FK_1 = B.PK and
  A.FK_2 = C.PK and
  A.ID = exist_clause_1.ID or
  A.ID = exist_clause_2.ID

解决方案 2

select <...>    
  from A, B, C
       ( (select ID from ...) UNION
         (select ID from ...)
        ) as exist_clause,
where
  A.FK_1 = B.PK and
  A.FK_2 = C.PK and
  A.ID = exist_clause.ID

SparkSQL 目前没有 EXISTS & IN。 "(Latest) Spark SQL / DataFrames and Datasets Guide / Supported Hive Features"

EXISTS & IN 总是可以使用 JOIN 或 LEFT SEMI JOIN 重写。 "Although Apache Spark SQL currently does not support IN or EXISTS subqueries, you can efficiently implement the semantics by rewriting queries to use LEFT SEMI JOIN." OR 总是可以使用 UNION 重写。 AND NOT 可以用 EXCEPT 重写。

A table 保存使某些 谓词 (由列名参数化的语句)为真:

的行
  • DBA 给出了每个基 table T 的谓词,列为 T.C,... : T(T.C,...)
  • A JOIN 保存使其参数谓词的 AND 为真的行;对于 UNION,OR;对于 EXCEPT,AND NOT。
  • SELECT DISTINCTkept columnsFROMT 保存 EXISTS 所在的行删除的列 [T 的谓词]。
  • TLEFT SEMI JOINU 保存 EXISTS 所在的行U-only 列 [T 的谓词 AND U 的谓词]。
  • TWHEREcondition 保存 predicate 所在的行T AND 条件

(重新查询一般见this answer。)

因此,通过记住对应于 SQL 的谓词表达式,您可以使用简单的逻辑重写规则来编写 and/or 重组查询。例如,就可读性或执行而言,此处使用 UNION 不需要 "clumsy"。

您的原始问题表明您了解可以使用 UNION 并且您已将变体编辑到您的问题中,从您的原始查询中删除 EXISTS 和 IN。这是另一个也删除 OR 的变体。

    select <...>    
    from A, B, C, (select ID from ...) as e
    where
      A.FK_1 = B.PK and
      A.FK_2 = C.PK and
      A.ID = e.id
union
    select <...>    
    from A, B, C, (select ID from ...) as e
    where
      A.FK_1 = B.PK and
      A.FK_2 = C.PK and
      A.ID = e.ID

您的解决方案 1 与您认为的不同。如果 exists_clause table 中只有一个是空的,即即使在另一个中有 ID 匹配可用,tables 的 FROM 叉积是空的并且没有行被返回。 ("An Unintuitive Consequence of SQL Semantics": Chapter 6 The Database Language SQL sidebar page 264 of Database Systems: The Complete Book 2nd Edition.) FROM 不只是为 table 的行引入名称,它是 CROSS JOINing and/or OUTER JOINing 它们,然后 ON(对于 INNER JOIN)和 WHERE 过滤掉一些。

返回相同行的不同表达式的性能通常不同。这取决于 DBMS 优化。许多细节,DBMS and/or 程序员可能知道,如果知道也可能不知道,可能会或可能不会最好地平衡,影响评估查询的最佳方式和编写查询的最佳方式。但是在 WHERE 中每行执行两个 ORed 子选择(如在您的原始查询中以及您后期的解决方案 2 中)不一定优于 运行 两个 SELECT 的一个 UNION(如在我的查询中)。