加入与子查询

Posted

技术标签:

【中文标题】加入与子查询【英文标题】:Join vs. Subquery 【发布时间】:2017-08-02 17:01:30 【问题描述】:

我在资源和性能方面一直在寻找联接与子查询,答案似乎取决于平台。但就 BigQuery 而言,似乎没有人谈论它们。

当我将查询范围扩大到 100 GB 时,我遇到了一个

Query Failed
Error: Resources exceeded during query execution.

我大概有

#standardSQL
SELECT * FROM table t1 WHERE 
(t1.a in (SELECT b FROM anothertable WHERE class='value') 
OR t1.a in (SELECT c FROM table2) )

我想知道在 BigQuery 中 JOIN 是否会更好,尤其是当我扩展到 TB 的数据时。

【问题讨论】:

为什么不实际尝试 JOIN 并分享结果 :o) 或者尝试EXISTS而不是IN,因为由于空处理,语义和执行略有不同。 @MikhailBerlyant 如果以前没有人做过,我会这样做,但我需要很长时间才能弄清楚如何更改语义。 如果您是初学者并且在使用连接构建查询时需要帮助 - 只需提出特定问题 :o) 您当前的问题(即 - 我想知道在 BigQuery 中连接是否会更好,特别是如果我扩展到 TB 的数据。)太笼统了 @ElliottBrossard 如果EXISTSIN 不同,除非我执行EXISTS (SELECT c FROM table2 WHERE t1.a=c) 之类的操作。为什么 null 处理很重要? 【参考方案1】:

注意这个查询和下一个查询的区别:

1)

#standardSQL
SELECT COUNTIF(author IN (
   SELECT author 
   FROM `fh-bigquery.reddit_comments.2017_01` 

))
FROM `fh-bigquery.reddit_comments.2017_01`

2)

#standardSQL
SELECT COUNTIF(author IN (
   SELECT DISTINCT author 
   FROM `fh-bigquery.reddit_comments.2017_01` 
))
FROM `fh-bigquery.reddit_comments.2017_01`

这是一个愚蠢的查询 - 两者都应该返回 157893170。尽管如此,1) 已经运行了超过 8 分钟(到目前为止),而 2) 运行了 36 秒。

秘诀?在执行IN() 时,请确保使用DISTINCT 删除重复项 - 如果没有,将有很多行要 JOIN 根本不会改变结果。

// TODO(gcp): This could be a BigQuery optimization.

【讨论】:

这是一个有趣的发现,但我仍然遇到同样的错误,主要是因为我的子查询已经查询了应该承载大部分不同行的表。 这些表有多大?您可以从这些表中执行 SELECT COUNT(DISTINCT) 吗?也许 OR 正在抛弃它 - 如果您将 2 个表合并,这样 IN 只在一个列表上运行一次呢? 大约 45000 与所有 or 语句不同。我将看到联合如何改变任何东西,尽管我只是认为资源爆炸与 SELECT 的主查询有关。我稍后会在 UNION 上发布。 而 UNION 也让资源消耗殆尽。【参考方案2】:

我想知道,您是否尝试过 Elliott 使用 EXISTS 的建议?

类似:

WITH table1 AS(
SELECT '1' as user, 1 AS id UNION ALL
SELECT '2' AS user, 2 as id UNION ALL
SELECT '3' AS user, 3 as id
),
anothertable AS(
SELECT '1' AS user, 'value' AS class , '4' AS c UNION ALL
SELECT '2' AS user, 'value2' AS class, '2' AS c UNION ALL
SELECT '4' AS user, 'value' AS class, '3' AS c UNION ALL
SELECT '5' AS user, 'value2' AS class, '5' as c
),
table2 AS(
SELECT '4' AS c UNION ALL
SELECT '2' AS c UNION ALL
SELECT '3' AS c UNION ALL
SELECT '5' as c
)

SELECT
  t1.*
FROM table1 t1
WHERE TRUE
AND EXISTS(SELECT 1 FROM anothertable ta WHERE (class = 'value' AND t1.user = ta.user))
OR EXISTS(SELECT 1 FROM table2 t2 WHERE t1.user = t2.c)

是否超出资源?

【讨论】:

来自 BigQuery,我得到 Error: Correlated subqueries that reference other tables are not supported unless they can be de-correlated, such as by transforming them into an efficient JOIN.

以上是关于加入与子查询的主要内容,如果未能解决你的问题,请参考以下文章

多表查询之复合查询与子查询

如何将查询与子查询连接起来?

MSSQL之五 连接查询与子查询

UDF 与子查询性能问题

Mysql 慢查询组与子查询连接

SQL 内连接与子查询