Processing math: 100%

4 votos

Consulta tarda mucho tiempo

Soy un novato en POSTGIS y me pregunto si alguien me podría ayudar.

He cargado todos los códigos postales con sus coordenadas geográficas (geografía) y crea un índice en esta coordenada.

Cuando yo ejecute la siguiente consulta funciona muy bien (dentro de unos pocos milisegundos más de un par de millones de casos)

SELECT
  postcode, huisnummer, huisletter, huisnummertoevoeging,
  ST_X(geolocatie :: geometry) as latitude,
  ST_Y(geolocatie :: geometry) as longitude,
  st_distance(geolocatie, ST_SetSRID(ST_Point(4.3387478, 51.9808117), 4326)) as afstand
FROM inspire
WHERE ST_DWithin(geolocatie, ST_SetSRID(ST_Point(4.3387478, 51.9808117), 4326), 1000)
ORDER BY afstand
LIMIT 5;

geolocatie es de tipo geografía y yo hemos definido el siguiente índice de geolocatie

CREATE INDEX inspire_geolocatie_index
    ON public.inspire USING gist
    (geolocatie)
    TABLESPACE pg_default;

Esto funciona bien siempre hay vecinos, pero la consulta parece tener dificultades para el caso de uso que no hay vecinos. Alguna sugerencia por favor?

2voto

Ilya Cherevkov Puntos 167

Usted menciona que la consulta tiene dificultades para el caso de que hay vecinos - esto es debido a que el 'dónde' declaración, que excluye a las observaciones más allá de 1000 unidades de su sistema de coordenadas. En la documentación de st_dwithin estados de los siguientes relativas a distancia: unidades son en los de referencia espacial.

Esto me lleva al segundo punto: 1000 unidades en WGS84 estaría muy lejos. Usted debe usar un sistema de coordenadas proyectadas con st_transform. Para los países Bajos, este sería EPSG 28992.

Para saber los puntos que están dentro de 1000 metros se puede ejecutar la siguiente consulta:

SELECT
  postcode, huisnummer, huisletter, huisnummertoevoeging,
  ST_X(ST_Transform(geolocatie,28992) :: geometry) as latitude, -- assuming your geometry is in 4326
  ST_Y(ST_Transform(geolocatie,28992)  :: geometry) as longitude,
  ST_Distance(
        ST_Transform(geolocatie,28992),
        ST_Transform(ST_SetSRID(ST_Point(4.3387478, 51.9808117),4326),28992)) as afstand , 
  ST_DWithin(
        ST_Transform(geolocatie,28992) , 
        ST_Transform(ST_SetSRID(ST_Point(4.3387478, 51.9808117),4326),28992),1000) as within_distance 
FROM inspire 
ORDER BY afstand

Rendimiento de los sabios, esto puede ser mejorada mediante la adición de una geometría a la mesa en avanzar con el proyecto de la geometría y la adición de un índice.

-- Add the column
ALTER TABLE inspire ADD COLUMN geom_28992 geometry;
-- Set the column
UPDATE inspire SET geom_28992 = st_transform(geom,28992);
-- Create an index
CREATE INDEX idx_geom_28992_inspire ON inspire USING GIST(geom_28992);

Para st_dwithin para trabajar de manera eficiente ambas geometrías necesitan ser indexado: el índice de referencia de la geometría debe estar en una mesa y, con el índice.

-- Reference geom
CREATE TABLE reference_geom AS
SELECT ST_Transform(ST_SetSRID(ST_Point(4.3387478, 51.9808117),4326),28992) geom_28992;
-- Create an index
CREATE INDEX idx_geom_28992_reference_geom ON reference_geom USING GIST(geom_28992);

Por último, se puede ejecutar la consulta

SELECT postcode, huisnummer, huisletter, huisnummertoevoeging, 
st_distance(i.geom_28992,g.geom_28992) distance,
true::boolean within_distance
FROM inspire i
INNER JOIN reference_geom  g ON st_dwithin(i.geom_28992,g.geom_28992,1000)
UNION ALL
SELECT postcode, huisnummer, huisletter, huisnummertoevoeging, 
null AS distance,
false::boolean within_distance
FROM inspire i,reference_geom
WHERE st_dwithin(i.geom_28992,g.geom_28992,1000) = FALSE

Para aplicaciones más interesantes a tener un vistazo más cercano al prójimo problemas en Postgis, por ejemplo aquí y aquí.

2voto

mathieu Puntos 53

Usted tiene un sólido derecho de consulta de ahí, y me parece que no puede reproducir el problema (por el título), suponiendo un bien creadas y indexado geografía de la columna.

Si yo fuera a mejorar las cosas aquí, Id de uso

SELECT
  postcode, huisnummer, huisletter, huisnummertoevoeging,
  ST_X(geolocatie::geometry) AS latitude,
  ST_Y(geolocatie::geometry) AS longitude,
  ST_Distance(geolocatie, ST_SetSRID(ST_MakePoint(4.3387478, 51.9808117), 4326)::geography) AS afstand
FROM inspire
ORDER BY geolocatie <-> ST_SetSRID(ST_MakePoint(4.3387478, 51.9808117), 4326)::geography
LIMIT 5;

El KNN operador <-> como ORDER BY parámetro es mejor en rendimiento cuando se utiliza correctamente; incluso me atrevería a renunciar a una limitación de filtro, especialmente como ST_DWithin, en mi experiencia, aumenta la sobrecarga y niega el planificador de la tan deseada índice (sólo) explora más a menudo que no.


Yo no recomendaría este sin la debida transformación (como, por ejemplo, @Miguel propuesto), sino un índice de forzar alternativa de opción de filtro sería

SELECT
  postcode, huisnummer, huisletter, huisnummertoevoeging,
  ST_X(geolocatie::geometry) AS latitude,
  ST_Y(geolocatie::geometry) AS longitude,
  ST_Distance(geolocatie, ST_SetSRID(ST_MakePoint(4.3387478, 51.9808117), 4326)::geography) AS afstand
FROM inspire
WHERE geolocatie::geography && ST_Expand(ST_SetSRID(ST_MakePoint(4.3387478, 51.9808117), 4326), 0.01)
ORDER BY geolocatie <-> ST_SetSRID(ST_MakePoint(4.3387478, 51.9808117), 4326)::geography
LIMIT 5;

es decir, utilizando el bbox intersección operador && directamente; en su mayor desventaja es la dependencia de la geometría de tipo (y por lo tanto la CRS unidades) ST_Expand, que te deja con un peligroso 0.01 grados (~1.1km, pero sólo en el ecuador), para ser utilizado como parámetro de distancia sin un medidor basado en la proyección.


Sin su añadiendo detalles a la cuestión, el problema de seguimiento será difícil; para empezar, el EXPLAIN ANALYZE <your_query> para ambos planes es casi obligatorio para el rendimiento de las consultas relacionadas con las preguntas, así como su PostgreSQl/PostGIS versiones.

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