有没有办法在单个空间查询上设置多个列值?
Is there a way to set multiple column values on a single spatial query?
我正在使用 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
创建一个新的临时文件table,在一个点的 2 以内为每行记录,然后设置值关闭 table 会更有效吗]?描述它,它听起来效率较低,因为 ST_DWithin()
使用索引的性能并不差。
您可以在一个语句中更新多个列,方法是将它们括在括号中
UPDATE myTable
SET (a,b) = (
select c,d
from anotherTable
WHERE st_dwithin(mytable.geom, anotherTable.geom,2)
);
JGH 提供了一种从(相关)子查询一次 UPDATE
多个列的智能方法。自 Postgres 9.5 以来可能。然而,也有相当大的缺点。
该表单无条件地 table 更新每一行。您将不得不在 WHERE
子句中重复计算以有条件地进行计算,这违背了只进行一次的目的。
在 PostgreSQL 的 MVCC 模型中 UPDATE
基本上意味着编写完整行的新版本,膨胀 table 和索引。本身很昂贵,但如果您不能或不清理,还会导致 VACUUM
- and/or 性能下降的大量额外工作。参见:
要么你真的想更新每一行,那基本上没问题。但是,如果您不受并发负载或对 table(视图、FK、...)的内部引用的约束,请考虑编写一个新的 table。通常总体上更便宜。
但是,某些(或 many/most?)行可能已经是最新的。那是巨大的浪费。请考虑:
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
加入。但是我们在应用更新之前删除了所有没有更改的行 - 这样可以为已经更新的每一行节省大部分工作。好吧,由于子查询相对昂贵,也许不是 most 的工作。但通常情况下,实际的写入操作比计算新值要昂贵得多。
这与您在上一段中的想法非常接近。但是在不创建临时文件的情况下效率更高 table,并且您还可以保存空写入。
如果您只需要在 streets.geom
中更改几行后更新 intersections
中可能受影响的行,那么还有更多优化潜力。不去,好像超出了这个问题的范围。
相关:
- How do I (or can I) SELECT DISTINCT on multiple columns?
我正在使用 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
创建一个新的临时文件table,在一个点的 2 以内为每行记录,然后设置值关闭 table 会更有效吗]?描述它,它听起来效率较低,因为 ST_DWithin()
使用索引的性能并不差。
您可以在一个语句中更新多个列,方法是将它们括在括号中
UPDATE myTable
SET (a,b) = (
select c,d
from anotherTable
WHERE st_dwithin(mytable.geom, anotherTable.geom,2)
);
JGH 提供了一种从(相关)子查询一次 UPDATE
多个列的智能方法。自 Postgres 9.5 以来可能。然而,也有相当大的缺点。
该表单无条件地 table 更新每一行。您将不得不在 WHERE
子句中重复计算以有条件地进行计算,这违背了只进行一次的目的。
在 PostgreSQL 的 MVCC 模型中 UPDATE
基本上意味着编写完整行的新版本,膨胀 table 和索引。本身很昂贵,但如果您不能或不清理,还会导致 VACUUM
- and/or 性能下降的大量额外工作。参见:
要么你真的想更新每一行,那基本上没问题。但是,如果您不受并发负载或对 table(视图、FK、...)的内部引用的约束,请考虑编写一个新的 table。通常总体上更便宜。
但是,某些(或 many/most?)行可能已经是最新的。那是巨大的浪费。请考虑:
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
加入。但是我们在应用更新之前删除了所有没有更改的行 - 这样可以为已经更新的每一行节省大部分工作。好吧,由于子查询相对昂贵,也许不是 most 的工作。但通常情况下,实际的写入操作比计算新值要昂贵得多。
这与您在上一段中的想法非常接近。但是在不创建临时文件的情况下效率更高 table,并且您还可以保存空写入。
如果您只需要在 streets.geom
中更改几行后更新 intersections
中可能受影响的行,那么还有更多优化潜力。不去,好像超出了这个问题的范围。
相关:
- How do I (or can I) SELECT DISTINCT on multiple columns?