EXISTS 和 IN 的 Spark 替换
Posted
技术标签:
【中文标题】EXISTS 和 IN 的 Spark 替换【英文标题】:Spark replacement for EXISTS and IN 【发布时间】:2016-01-18 18:23:22 【问题描述】:我正在尝试运行使用 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
【问题讨论】:
您的第一个查询模板不应该有exists (select E.ID from <subquery> E where E.ID = A.ID))
形式的 EXISTS 调用吗?
【参考方案1】:
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 重写。
一个表包含使某些谓词(由列名参数化的语句)为真的行:
DBA 为每个带有列T.C,...
的基表 T
提供谓词:T(T.C em>,...)
JOIN
包含使其参数谓词的 AND 为真的行;对于UNION
,OR;对于 EXCEPT
,AND NOT。
SELECT DISTINCT
kept columns
FROM
T
保存 EXISTS 删除的列 [T的谓词的行>]。
T
LEFT SEMI JOIN
U
保存 EXISTS U-only 列 [T 的谓词 的行AND U 的谓词]。
T
WHERE
condition
包含 T 的谓词 AND 条件 所在的行。
(重新查询一般见this answer。)
因此,牢记与 SQL 对应的谓词表达式,您可以使用简单的逻辑重写规则来组合和/或重新组织查询。例如,在这里使用 UNION 在可读性或执行方面都不需要“笨拙”。
您的原始问题表明您了解可以使用 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
表为空,即即使在另一个表中有ID
匹配,表的FROM 叉积也为空并且不返回任何行。 ("An Unintuitive Consequence of SQL Semantics": Chapter 6 The Database Language SQL sidebar page 264 of Database Systems: The Complete Book 2nd Edition.) A FROM 不只是介绍表行的名称,它是 CROSS JOINing 和/或 OUTER JOINing 它们,然后是 ON(对于 INNER JOINs)和 WHERE 过滤掉一些。
返回相同行的不同表达式的性能通常不同。这取决于 DBMS 优化。 DBMS 和/或程序员可能知道的许多细节,如果知道,也可能不知道,可能会或可能不会最佳平衡,影响评估查询的最佳方式和编写查询的最佳方式。但是在 WHERE 中的每行执行两个 ORed 子选择(如在您的原始查询中以及您后期的解决方案 2 中)并不一定比运行两个 SELECT 的一个 UNION(如在我的查询中)更好。
【讨论】:
感谢您的回复!我最终为每个选择语句使用了子查询,并在所有基本关系和由子查询计算的关系之间执行了一个巨大的连接。我认为您的解决方案有些不同,尽管我不完全理解。你能画一个更精确的查询模板吗? (我正在编辑问题以添加我当前的解决方案) 另外,您提到性能通常会有所不同。你能提示一下为什么会这样吗? 我已更新我的答案以解决您的 cmets。关于性能,您应该阅读有关关系查询优化的内容,这实际上仅意味着关系查询实现。有许多在线通用和特定产品的书籍,google 'sql performance' 等。以上是关于EXISTS 和 IN 的 Spark 替换的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 查询性能问题:需要替换 NOT EXISTS