LEFT JOIN左表日期范围为何与WHERE子句限制处理字节量不同?
为什么LEFT JOIN左表的日期范围无法像WHERE子句一样控制右表的处理字节量?
核心原因拆解
你遇到的问题本质是BigQuery的分区过滤逻辑和LEFT JOIN执行计划的限制,具体来说:
分区过滤需要明确的直接条件
你的big_table按tstamp按日分区,分区过滤能生效的关键是:查询中必须有直接作用在分区键上的明确过滤规则,且这个规则能被BigQuery优化器识别并下推到分区扫描环节。- Query 2里,子查询的
WHERE tstamp BETWEEN "2022-09-01 00:00:00 UTC" AND "2022-11-24 00:00:00 UTC"是直接给分区键加的硬过滤,优化器可以直接定位到对应日期的分区,只读取1.07GB的数据。 - Query 1里,左表的时间范围是通过
ON cal.tstamp = t.tstamp间接关联到右表的。BigQuery优化器没办法在扫描右表分区前,把左表的tstamp集合当成过滤条件用——因为LEFT JOIN的逻辑是要先拿到右表的数据,再和左表做匹配,这就导致它不得不扫描big_table的全部分区,产生3.9GB的处理量。
- Query 2里,子查询的
LEFT JOIN的语义限制了优化空间
LEFT JOIN要求保留左表的所有行,哪怕右表没有匹配项。这种语义下,BigQuery的默认执行逻辑是:- 先读取左表的所有
tstamp值,但没办法提前把这些值作为分区过滤条件传给右表扫描——尤其是你的左表是用GENERATE_TIMESTAMP_ARRAY动态生成的,优化器没法提前预判它的时间范围,只能先扫完右表全部分区,再做关联匹配。
- 先读取左表的所有
动态生成左表的影响
你的calendar_halfhour是通过函数动态生成的时间序列,不是预先存储的带统计信息的表。BigQuery优化器没法提前获取这个表的tstamp范围,自然也就没法基于这个范围做分区过滤下推。哪怕左表是预先存储的,这种基于JOIN关联的间接过滤,优化器也很难自动转换成分区扫描的条件。
优化建议
如果想让左表的时间范围控制右表的分区扫描,最可靠的方式就是像Query2那样,把左表的时间范围作为明确的过滤条件直接加到右表上;或者用动态SQL生成对应的过滤规则,把左表的时间范围转换成硬条件。
内容的提问来源于stack exchange,提问作者164_user
相关产品推荐
相关产品推荐

