我正在尝试按日期查看用户活动。第一步是使用交叉连接和where子句构建自创建用户帐户以来每天的表。我的第一次尝试是这样的:
SELECT
u.user_id as user_id,
date(u.created) as signup_date,
cal.date as date,
from rsdw.user u
cross join (select date(dt) as date from [rsdw.calendar] where date(dt) < CURRENT_DATE() ) cal
where
date(u.created) <= cal.date
(日历表只是2006年以来所有日期的列表(3288行)。用户表的行数约为1米。)
这个查询需要一个永远......我已经在1000秒左右放弃了它。我尝试稍微调整一下查询。如果我在交叉连接中添加“each”:
SELECT
u.user_id as user_id,
date(u.created) as signup_date,
cal.date as date,
from rsdw.user u
cross join each (select date(dt) as date from [rsdw.calendar] where date(dt) < CURRENT_DATE() ) cal
where
date(u.created) <= cal.date
我得到了错误:
Error: Cannot CROSS JOIN two tables with EACH qualifiers.
最后,如果我保留“每个”但交换表格,它会在90秒内完成!
SELECT
u.user_id as user_id,
date(u.created) as signup_date,
cal.date as date,
from (select date(dt) as date from [rsdw.calendar] where date(dt) < CURRENT_DATE() ) cal
cross join each rsdw.user u
where
date(u.created) <= cal.date
任何人都可以解释为什么第三次迭代要快得多,为什么第二次迭代会导致错误?
答案 0 :(得分:5)
您正在尝试使用联接与子选择子句交互的角点行为。对命名表的连接受益于基于表大小的一些优化,而子选择是不可预测的并且可能导致不良性能。我已经为我们提交了一个内部错误来改进这个案例。
在第一个慢速情况下,您的微小的日期子选项被复制并广播到少数每台处理大量用户的机器上。它需要永远,因为很少有并行性。
第二种情况是出于内部原因的查询解析错误,基本上它试图让机器处理小范围的日期和小范围的用户,这将无法完成交叉连接。
在第三种快速案例中,您的微小的日期子选择被复制并广播到许多机器,每台机器处理一小部分用户。由于大的并行性,它完成得非常快。
一旦我们完成了我提交的错误,第三种情况就会自动发生。
答案 1 :(得分:0)
基于https://cloud.google.com/bigquery/query-reference,交叉联接甚至不支持&#34;每个&#34;条款,所以我有点惊讶第三个查询甚至运行。
交叉连接形成笛卡尔积(左表中的每个记录与来自正确查询的每个记录连接) - 这是一种非常低效的数据连接方式(尽管有时无法避免,例如你的方式试图创建您的数据集)。 Users表中有多少条记录?只有当左表是较小的表(并且压缩不到8MB)时,EACH子句才有效。您的日历表包含3650条记录,因此如果您的用户数多于此数,则需要位于左侧 - 就像您在第三个查询中所做的那样。