3 votos

Diferencia y unión de PostGIS

Tengo dos tablas, A y B.

Quiero unir(/disolver) B y luego diferenciar A,B. Para obtener lo que queda de A cuando se borra la superposición de B:

select a.someid, st_difference(a.wkb_geometry,st_union(b.wkb_geometry))
from a, b
where b.group_id=43 and b.type_id=12 and st_intersects(a.wkb_geometry, b.wkb_geometry)

Me da un error en la línea 1:

ERROR: la columna "A.wkb_geometry" debe aparecer en la cláusula GROUP BY o ser utilizada en una función agregada

¿Cómo se arregla esto? Sin st_union a veces obtengo a's duplicadas (en id, no en geometría) en la salida, lo cual no quiero. ¿Tal vez sea mejor unir la salida?

1 votos

¿qué ocurre cuando se añade una cláusula "GROUP BY"? ¿Intentó utilizar SELECT DISTINCT?

0 votos

Sólo intenté agrupar por geometría, pero cuando también agrupé por id funcionó

0 votos

En realidad yo diría que la unión ambos entradas (¿con una agrupación basada en id?); al hacerlo, se recrea la unión de b para cada fila de a. además, un índice no ayuda mucho aquí de todos modos.

4voto

Anton8000 Puntos 165

Necesitaba agrupar tanto por id como por geometría, sólo había intentado agrupar por uno de ellos.

select a.someid, st_difference(a.wkb_geometry,st_union(b.wkb_geometry))
from a, b
where b.group_id=43 and b.type_id=12 and st_intersects(a.wkb_geometry, b.wkb_geometry)
group by a.someid, a.wkb_geometry

3voto

mathieu Puntos 53

tl;dr: Pruebe la consulta en Sin embargo, primero. Esto, aunque sea, sólo tiene sentido si la geometría de la hoja no necesita disolverse y ST_Union puede sustituirse por ST_Collect .


Siguiendo mis comentarios:

A lo que me refería es a "externalizar" el sindicato en un CTE es decir, un WITH cláusula, así:

WITH
  blade AS (
    SELECT ST_Collect(wkb_geometry) AS geom
    FROM b
    WHERE group_id = 43 and type_id = 12
  )

SELECT a.someid,
       ST_Difference(a.wkb_geometry, b.geom) AS geom
FROM a
JOIN blade AS b
  ON ST_Intersects(a.wkb_geometry, b.geom);

Un CTE se ejecutará una vez por cada transacción, y puede ser visto como una tabla temporal eliminada en el commit; esto ayuda a evitar la creación de conjuntos de filas una y otra vez, y se ve mejor.

Utilicé ST_Collect en lugar de ST_Union en la mayoría de los casos, esto debería devolver el mismo MULTI geometría a la vez que son órdenes de magnitud más rápidas.

También utilicé un (INNER) JOIN en lugar de un WHERE filtro; esto es sólo para la legibilidad , en la mayoría de los casos .

Obsérvese también que no hay (posiblemente costosos) GROUP BY operaciones.


Sin embargo:

El principal motor del rendimiento, y en realidad el que hace su trabajo, es el Planificador de consultas La Planificador optimizará al máximo su consulta aplanando, sustituyendo, moviendo e incluso no ejecutando partes de la misma. Y en la mayoría de los casos es correcto.

Su eficacia está ligada principalmente a la actualización de las estadísticas de la tabla; se puede (y se debe, por ejemplo, después de crear índices o UPDATE/INSERT/DELETE operaciones) actualizarlas manualmente ejecutando VACUUM ANALYZE/FULL en una o todas las mesas.

Ahora, el punto clave; hay consultas que el planificador no puede optimizar, por diseño o por lógica, y Los CTEs son uno de esos (las funciones son otra, por lo que, por ejemplo, la unión en su función de diferencia no puede optimizarse aunque sea posible).

En su caso, la unión dentro de una subconsulta real puede ser por tanto beneficiosa (y la mejor opción):

SELECT a.someid,
       ST_Difference(a.wkb_geometry, b.geom) AS geom
FROM a
JOIN (
   SELECT ST_Collect(wkb_geometry) AS geom
   FROM b
   WHERE group_id = 43 and type_id = 12
) AS b
ON ST_Intersects(a.wkb_geometry, b.geom);

Notas sobre el índice y el rendimiento:

En general, la ejecución de consultas de relaciones geométricas y/o de manipulación en grandes y/o MULTI geometrías de la red se comportan peor que en muchas geometrías individuales pequeñas; para cada conjunto de puntos de entrada, cada vértice de la geometría grande tiene que ser atravesado y comprobado.

Dado que un índice espacial funciona con bbox árboles, el filtrado de la (no) relación es rapidísimo para geometrías pequeñas simplemente comparando sólo cuatro vértices en una rama del árbol, y sólo hacer la prueba de intersección geométrica en unos pocos elegidos; teniendo una bbox sin embargo, lo más probable es que incluya muchas o todas las demás comparadas, incluso si las propias geometrías no se cruzan geográficamente. En ese caso, PostGIS tendrá que hacer el costoso filtro de intersección en demasiadas geometrías, lo que anula el propósito de un índice.

Dicho esto, ST_Difference es complicado, ya que lo mejor es que la hoja sea una geometría unificada (para evitar el corte de productos cruzados de la misma geometría, dando lugar a duplicados). Una unión de geometrías indexadas hará que la gemetría combinada no sea SARGable Es decir, no puede tener o utilizar un índice.

Pero es posible que, cuando se trabaje con un subconjunto en el que se garantice que cada geometría se cruza con la hoja, una unión de las mismas funcione igual o incluso más rápido, ya que no hay una búsqueda de índice (en este caso innecesaria) primero, y al tener esa segunda gran MULTI geometría entonces en la memoria ya.

Teniendo en cuenta esto, corriendo:

SELECT ST_Difference(a.geom, b.geom) AS geom
FROM (
  SELECT ST_Collect(wkb_geometry) AS geom
  FROM a
  WHERE <column_filter_condition>
) AS a
CROSS JOIN (
  SELECT ST_Collect(wkb_geometry) AS geom
  FROM b
  WHERE group_id = 43 and type_id = 12
) AS b;

podría ser incluso más rápido, si puede filtrar a por adelantado (sin comprobar la intersección) en un subconjunto superpuesto.


Esto se fue rápidamente de las manos en el ámbito, no estoy seguro de que esto ayude. Pero ya que preguntaste...

¿Podría responder si alguno de los anteriores hizo ...o no ha funcionado?

1 votos

He escrito esto de la cabeza... Intentaré añadir referencias para algunos puntos clave lo antes posible.

1 votos

Actualizado con algunos enlaces

0 votos

Gracias. Sin embargo, no puedo conseguir que funcione. Estoy recibiendo un error de topología "TopologyException: side location conflict". Estoy seguro de que es el ST_Collect, he comprobado la topología de los demás. Intento cambiarla a ST_Union, lo que hace que se ejecute pero no se complete (al menos durante unos 5 minutos cuando aborto).

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X