我有两个表,shapes
和squares
,我正在基于GEOGRAHPY
列的交集进行联接。
shapes
表包含车辆的行驶路线:
shape_key STRING identifier for the shape
shape_lines ARRAY<GEOGRAPHY> consecutive line segments making up the shape
shape_geography GEOGRAPHY the union of all shape_lines
shape_length_km FLOAT64 length of the shape in kilometers
Rows: 65k
Size: 718 MB
我们将shape_lines
分隔在ARRAY
中,因为形状有时会自身折回,因此我们想使这些线段分开而不是deduplicating them。
squares
表包含1×1 km正方形的网格:
square_key INT64 identifier of the grid square
square_geography GEOGRAPHY four-cornered polygon describing the grid square
Rows: 102k
Size: 15 MB
形状代表车辆的行驶路线。对于每种形状,我们都在单独的表格中计算了有害物质的排放量。目的是假设每个栅格平方的排放量沿路线均匀分布,以计算出每个栅格平方的排放量。为此,我们需要知道路线形状的哪些部分与每个网格单元相交。
这里是用于计算的查询:
SELECT
shape_key,
square_key,
SAFE_DIVIDE(
(
SELECT SUM(ST_LENGTH(ST_INTERSECTION(line, square_geography))) / 1000
FROM UNNEST(shape_lines) AS line
),
shape_length_km)
AS square_portion
FROM
shapes,
squares
WHERE
ST_INTERSECTS(shape_geography, square_geography)
不幸的是,此查询在6小时后超时,而不是产生有用的结果。
在最坏的情况下,查询可以产生66亿行,但实际上不会发生。我估计每个形状通常相交约50个网格正方形,因此输出应为65k * 50 = 3.3M行; BigQuery不应该处理的所有内容。
我已经考虑过BigQuery执行的the geographic join optimizations:
空间联接是
WHERE
子句中具有谓词地理功能的两个表的联接。
检查。我什至将我的INNER JOIN
改写为上面所示的等效“逗号”联接。
当您保留地理数据时,空间连接的性能会更好。
检查。 shape_geography
和square_geography
都直接来自现有表。
BigQuery使用以下标准SQL谓词功能为INNER JOIN和CROSS JOIN运算符实现了优化的空间JOIN:[...]
ST_Intersects
检查。只需一个ST_Intersect
调用,没有其他条件。
未优化空间连接:对于LEFT,RIGHT或FULL OUTER连接;如果涉及到ANTI连接;否定空间谓词时。
检查。这些情况均不适用。
因此,我认为BigQuery应该能够使用其使用的任何空间索引数据结构来优化此联接。
我也考虑过advice about cross joins:
避免产生比输入更多的输出的联接。
此查询肯定产生比输入更多的输出;这是其本质,无法避免。
[需要
CROSS JOIN
时,请预先汇总数据。为了避免与产生比输入更多的输出的联接相关的性能问题:
- 使用GROUP BY子句预聚合数据。
检查。我已经预先汇总了按形状分组的排放数据,因此shapes
表中的每个形状都是唯一且不同的。
- 使用窗口功能。窗口功能通常比使用交叉联接更有效。有关更多信息,请参见analytic functions。
我认为无法对此查询使用窗口函数。
我怀疑BigQuery是根据输入行数而不是中间表或输出的大小来分配资源。那可以解释我所看到的病理行为。
如何使此查询在合理的时间内运行?
我认为squares
被倒置,导致地球多边形几乎满了:
select st_area(square_geography), * from `open-transport-data.public.squares`
打印类似5.1E14
的结果-这是完整的地球区域。因此,任何一条线都几乎与所有正方形相交。有关详细信息,请参见BigQuery文档:https://cloud.google.com/bigquery/docs/gis-data#polygon_orientation
您可以通过运行ST_GeogFromText(wkt, FALSE)
来反转它们-选择较小的多边形,而忽略多边形的方向,这相当快地起作用:
SELECT
shape_key,
square_key,
SAFE_DIVIDE(
(
SELECT SUM(ST_LENGTH(ST_INTERSECTION(line, square_geography))) / 1000
FROM UNNEST(shape_lines) AS line
),
shape_length_km)
AS square_portion
FROM
`open-transport-data.public.shapes`,
(select
square_key,
st_geogfromtext(st_astext(square_geography), FALSE) as square_geography,
from `open-transport-data.public.squares`) squares
WHERE
ST_INTERSECTS(shape_geography, square_geography)