【问题标题】:Is there a way to set multiple column values on a single spatial query?有没有办法在单个空间查询上设置多个列值?
【发布时间】:2020-08-16 09:41:37
【问题描述】:

我正在使用 PostGIS 的 ST_DWIthin() 将属性与点相关联。

UPDATE scratch.intersections AS i
SET legs = (
    SELECT COUNT(r.geom)
    FROM received.streets r
    WHERE ST_DWithin(i.geom, r.geom, 2));

UPDATE scratch.intersections AS i
SET streets = (
    SELECT ARRAY_AGG(DISTINCT r.NAME ORDER BY r.NAME) 
    filter (WHERE r.NAME IS NOT NULL)
    FROM received.streets r
    WHERE ST_DWithin(i.geom, r.geom, 2));

似乎应该可以使用单个空间查询更新多个列,但我想不出一种方法来构造它,因为我一次只能更新一个列。

有没有办法将这两个查询变成一个查询,只需要一次空间计算?

使用INNER JOIN 创建一个新的临时表,其中每行记录在一个点的 2 以内,然后从该表中设置值会更有效吗?描述它,这听起来效率较低,因为使用索引 ST_DWithin() 的性能并不差。

【问题讨论】:

  • 计数是否进入streets 或名称数组?这个UPDATE 多久运行一次?整张桌子?我可能有更多的建议。
  • 甚至没有发布正确的代码 sn-p 抱歉,已更新。它只是将腿设置为等于进入十字路口的街道数量,然后构建一组街道名称。我经常运行这样的查询,但单个查询只运行几次,总是针对整个表。

标签: sql postgresql sql-update postgis spatial


【解决方案1】:

您可以通过将它们括在括号中来更新一条语句中的多个列

UPDATE myTable
SET (a,b) = (
  select c,d 
  from anotherTable 
  WHERE st_dwithin(mytable.geom, anotherTable.geom,2)
);

【讨论】:

    【解决方案2】:

    JGH 提供了一种从(相关)子查询中同时UPDATE 多个列的智能方法。从 Postgres 9.5 开始可能。但是,也有相当大的缺点。

    该表单无条件地更新表格中的每一行。您必须在 WHERE 子句中重复计算才能有条件地执行此操作,这违背了只执行一次的目的。

    在 PostgreSQL 的 MVCC 模型中UPDATE 基本上意味着编写完整行、膨胀表和索引的新版本。本身就很昂贵,但也会为VACUUM 带来大量额外的工作 - 和/或如果你不能或不清理的话,性能会下降。见:

    要么你真的想更新每一行,那基本上没问题。但是,如果您不受并发加载或对表的内部引用(视图、FK、...)的约束,请考虑改为编写一个新表。总体而言通常更便宜。

    但是,某些(或许多/大多数?)行可能已经是最新的。那么这是一个巨大的浪费。请考虑:

    UPDATE scratch.intersections AS i
    SET    legs    = r.legs  
         , streets = r.streets
    FROM   scratch.intersections x
    JOIN   LATERAL (
       SELECT count(*) AS legs  -- assuming r.geom is NOT NULL
            , array_agg(DISTINCT s.NAME ORDER BY s.NAME)
                        FILTER (WHERE s.NAME IS NOT NULL) AS streets
       FROM   received.streets s
       WHERE  ST_DWithin(x.geom, s.geom, 2)
       ) r ON x.legs    IS DISTINCT FROM r.legs
           OR x.streets IS DISTINCT FROM r.streets 
    WHERE i.id = x.id;  -- id being the PK (or at least UNIQUE)
    

    这不会触及实际上没有变化的行。

    我们需要在FROM 子句中增加scratch.intersections 的实例以允许LATERAL 加入。但是我们在应用更新之前删除了所有未更改的行 - 这样可以节省已经更新的每一行的大部分工作。好吧,由于子查询相对昂贵,可能不是大部分的工作。但通常情况下,实际的写入操作比计算新值要昂贵得多。

    这与您在上一段中的想法非常接近。但不创建临时表效率更高,而且还可以节省空写入。

    如果您只需要在更改streets.geom 中的几行之后更新intersections 中可能受影响的行,那么还有更多的优化潜力。不去那里,似乎超出了这个问题的范围。

    相关:

    【讨论】:

      猜你喜欢
      • 2017-05-12
      • 2010-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-30
      • 1970-01-01
      相关资源
      最近更新 更多