查询在6个小时后超时,如何对其进行优化?

问题描述 投票:2回答:2

我有两个表,shapessquares,我正在基于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_geographysquare_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是根据输入行数而不是中间表或输出的大小来分配资源。那可以解释我所看到的病理行为。

如何使此查询在合理的时间内运行?

google-bigquery gis cartesian-product
2个回答
0
投票

下面肯定不适合注释格式,所以我必须将其作为答案...

我对您的查询进行了三处调整

  • 使用JOIN ... ON而不是CROSS JOIN ... WHERE
  • 注释square_portion计算
  • 使用带有Allow Large Results选项的目标表

尽管您期望输出仅330万行-实际上,它大约是6.6 B(6,591,549,944)行-您可以在下面看到我的实验结果

enter image description here

请注意有关帐单级别的警告-因此,如果可以的话,最好使用“预定”显然,不加注释的square_portion计算将增加插槽的使用量-因此,您可能可能需要重新查看需求/期望


0
投票

我认为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)
© www.soinside.com 2019 - 2024. All rights reserved.