8 votos

¿Cómo utilizar los índices con inner join en Postgis?

Tengo 2 conjuntos de puntos en 2 tablas separadas. La tabla_a tiene 100k puntos y la tabla_b tiene 300k puntos. Intento encontrar los puntos más cercanos en relación a encontrar cualquier punto de la tabla_b que esté a menos de 50 metros de la tabla_a. Después de eso calcular la columna de caída, agruparlos por la columna a_id de la tabla_a y devolver el valor más alto.

Escribí la siguiente consulta que cumple con esta criteira

SELECT DISTINCT ON (a_id) *
FROM (
       SELECT
         table_b.b_id,
         table_b.height - st_3ddistance(table_b.geom, table_a.geom) fall,
         table_b.geom,
         table_a.a_id
       FROM table_a
         INNER JOIN table_b ON _st_3ddwithin(table_a.geom, table_b.geom, 50)) a
WHERE fall >= 0
ORDER BY a_id, fall DESC;

He añadido índices de geometría 3d:

CREATE INDEX table_a_geom ON table_a USING GIST (geom gist_geometry_ops_nd);
CREATE INDEX table_b_geom ON table_b USING GIST (geom gist_geometry_ops_nd);

Sin embargo, mi problema es que no puedo hacer una consulta para utilizarlos. El planificador de consultas sigue eligiendo el escaneo de la secuencia que es lento. Hice algunas pruebas cambiando El sistema de la red de distribución de agua es un sistema de distribución de agua que se utiliza para la gestión del agua. con st_3ddwithin , <<->> < 50 creando 50 m de amortiguación e intersección , st_3ddistance < 50 pero cada vez que el planificador está eligiendo la exploración de la secuencia. ¿Hay alguna forma de utilizar índices con mayor rendimiento o de cambiar la consulta para utilizar índices?

Mi plan de consulta:

Unique  (cost=10462593.70..10473018.43 rows=1 width=144)
  ->  Sort  (cost=10462593.70..10467806.06 rows=2084945 width=144)
        Sort Key: table_a.nmbayuid, ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom))) DESC
        ->  Nested Loop  (cost=0.00..10243762.28 rows=2084945 width=144)
              Join Filter: (_st_dwithin(table_a.geom, table_b.geomgr, '50'::double precision) AND ((table_b.height - st_3ddistance(table_b.geomgr, table_a.geom)) >= '0'::double precision))
              ->  Seq Scan on e_veg_points_mv12404 table_b  (cost=0.00..1459.47 rows=47147 width=96)
              ->  Materialize  (cost=0.00..10.97 rows=398 width=56)
                    ->  Seq Scan on e_wires_mv12404 table_a  (cost=0.00..8.98 rows=398 width=56)

1 votos

¿Qué es exactamente e_wires_mv12404 que está en el plan de consulta pero no en el SQL? ¿Qué aspecto tiene el plan de consulta sólo para la consulta interna? Sugiero no utilizar funciones que empiecen por _ST. Por último, es posible que pueda obtener un mejor rendimiento utilizando ST_DWithin en 2D, utilizando 35 metros, que es más o menos lo mismo que 50 metros de los bordes opuestos de un cubo. Como está buscando el punto más cercano en un radio de 50 metros, este podría ser un buen candidato para una unión lateral y utilizar la construcción ORDER BY a.geom <-> b.geom.

1 votos

El año pasado tuve un problema similar, He desenterrado este post para ti Hágame saber si no responde a sus preguntas.

0 votos

@JohnPowellakaBarça, ¿puedes explicar por qué no sugieres funciones que empiecen por "_ST"?

6voto

Patrick Puntos 20392

En primer lugar, como se ha señalado en los comentarios, el guión bajo inicial antes de la función ST, es decir, _ST_3DWithin hará que no se utilice el índice. No puedo encontrar ninguna mención reciente de esto, pero en documentos antiguos si se busca, por ejemplo, _ST_Intersects se indica:

Para evitar el uso de índices, utilice la función _ST_Intersects.

EDIT: Como aclara @dbaston en los comentarios, las funciones con el guión bajo delante son funciones internas que no utilizan el índice cuando son llamadas y esto sigue siendo así (aunque es difícil de encontrar en los docs).

Su consulta podría beneficiarse de la sintaxis LATERAL JOIN, que se presta bien a los problemas de k vecinos más cercanos (kNN) como éste.

SELECT 
   a.a_id, 
   b.b_id
   b.height - ST_3Ddistance(b.geom, a.geom) AS fall,
  FROM table_a a
     LEFT JOIN LATERAL
       (SELECT
            b_id,         
            geom,
            height        
          FROM table_b
          WHERE ST_3Ddwithin(a.geom, geom, 50)
          AND height - ST_3Ddistance(geom, a.geom) > 0
          ORDER BY height - ST_3Ddistance(b.geom, a.geom) DESC 
          LIMIT 1
        ) b ON TRUE;

Esto permite encontrar las k geometrías más cercanas desde la tabla a (en este caso 1, debido al LÍMITE 1) a la tabla b, ordenadas por la distancia 3D entre ellas. Se escribe utilizando un LEFT JOIN, ya que es concebible que haya algunas geometrías en la tabla a que no estén a menos de 50 metros de la tabla b.

Las consultas laterales permiten hacer referencia a columnas de la cláusula FROM anterior, lo que las hace más potentes que las subconsultas estándar, véase los documentos .

No puedo comprobarlo con tus datos, pero cuando he ejecutado consultas similares, la sentencia EXPLAIN indica un uso adecuado del índice.

3voto

Jerome Puntos 106

El año pasado tuve un problema similar, He desenterrado este post para ti ¿me avisa si no responde a sus preguntas?

2voto

Keith Donegan Puntos 5613

Este enlace En la documentación de PostGIS se recomiendan los siguientes pasos para garantizar la optimización de los índices y del planificador de consultas:

  1. Asegúrese de que se recogen estadísticas sobre el número y la distribución de los valores en una tabla, para proporcionar al planificador de consultas una mejor información para tomar decisiones sobre el uso de los índices. VACUUM ANALYZE calculará ambas cosas.

  2. Si la aspiración no ayuda, puede forzar temporalmente al planificador a utilizar la información del índice utilizando el comando set enable_seqscan a off;. De esta manera puede comprobar si el planificador es capaz de generar un plan de consulta acelerado por índices para su consulta. Sólo debe utilizar este comando para la depuración: en general, el planificador sabe mejor que usted cuándo utilizar los índices. Una vez que haya ejecutado su consulta, no olvide volver a activar ENABLE_SEQSCAN para que las demás consultas utilicen el planificador con normalidad.

  3. Si al poner enable_seqscan en off la consulta se ejecuta, es probable que su Postgres no esté ajustado a su hardware. Si el planificador se equivoca en el coste de los escaneos secuenciales frente a los de índice, intente reducir el valor de random_page_cost en postgresql.conf o utilice set random_page_cost a 1.1;. El valor por defecto del parámetro es 4, intente ponerlo a 1 (en SSD) o 2 (en discos magnéticos rápidos). Disminuir el valor hace que el planificador se incline más por el uso de escaneos de índice.

  4. Si el ajuste de enable_seqscan a off; no ayuda a su consulta, puede suceder que usted utiliza una construcción Postgres no es todavía capaz de desenredar. Una subconsulta con inline select es un ejemplo - necesita reescribirla para que el planificador pueda optimizar, por ejemplo, un LATERAL JOIN.

Por lo tanto, pruebe primero los pasos 1 a 3 antes de reescribir su consulta para utilizar los índices. Si eso no funciona, puedes intentar modificar la consulta.

Creo (en la medida de mi capacidad para batir el SQL sin ejecutar el código) que la consulta de abajo devolverá resultados idénticos a los tuyos, pero no sé si será más eficiente.

SELECT DISTINCT on (a_id),
    table_b.b_id as b_id,
    table_b.height - st_3ddistance(table_b.geom, table_a.geom) as fall,
    table_b.geom as b_geom,
    table_a.a_id as a_id
    FROM table_a
         INNER JOIN table_b ON _st_3ddwithin(table_a.geom, table_b.geom, 50)) a
WHERE fall >= 0
ORDER BY a_id, fall DESC;

0 votos

Muy interesante después de cambiar _st_3ddwithin a st_dwithin como otros comentarios sugirieron y ejecutar VACUUM ANALYZE después, ¡el planificador finalmente empieza a coger el índice!

0voto

DevSolar Puntos 18897

Si utiliza Postgres 10 (o una versión más reciente), le recomiendo encarecidamente que cargue los datos en tablas paralelas.

Probablemente tendrás que dedicar tiempo a afinarlo (partición de datos y número de trabajadores), pero creo que merece la pena el esfuerzo. Teóricamente, KNN es altamente paralelizable, alcanzando complejidades de tiempo constantes, incluso O(1) si la cantidad de trabajadores es igual al número de elementos donde se calculará una operación KNN.

Se ofrecen algunas referencias prácticas sobre la carga de datos y la realización de consultas aquí . Proporciona algunos detalles sobre el plan tunning (para obligar a actuar a más trabajadores) aquí . Es importante señalar que las secuencias de comandos paralelas implican mucha coordinación de tareas, por lo que el límite teórico extremo de proporcionar la paralelización más extrema no se cumple en la práctica, debido a las redes y a otras características de diseño de los sistemas.

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