4 votos

Postgis no puede encontrar la manera óptima, parece ser siempre el uso de Btree índice en lugar de índice espacial

Estoy usando el Postgis ST_DWithin función como esta:

SELECT *,
    ST_X(geometry) as longitude, 
    ST_Y(geometry) as latitude,
    ST_Distance_Sphere(
        ST_SetSRID(
            ST_MakePoint(-118.478255,34.303046999999999),
            4326),
        geometry) / 1609.34 as DISTANCE 
FROM  poi 
WHERE ( category =10980400 ) 
    AND ST_DWithin(geometry::geography,
        (ST_SetSRID(
            ST_MakePoint(-118.478255,34.303046999999999),
            4326)::geography
        ),
        80467.2,
        false)
ORDER BY DISTANCE
LIMIT 10

La estoy usando para encontrar puntos más próximos (como los Cajeros automáticos, restaurantes) dentro de un radio.

He índices disponibles para la geometría, la geografía y un índice de árbol b para la categoría. Cuando me "explicar analizar" la consulta puedo ver que la consulta sólo utiliza la categoría de índice. No estoy seguro si es que ocurre siempre o es un tiempo de ejecución de la decisión.

El problema es que hay casos en que la consulta se realiza mejor si puedo quitar la categoría de índice y la consulta utiliza índice espacial.

Del mismo modo, hay casos cuando tengo todos los índices y la consulta es mejor mediante el uso de la categoría de índice. Pero, a continuación, los casos por encima de degradar.

¿Por qué no puede postgis decidir la manera óptima ?? He corrido VACÍO ANALIZAR en la tabla después de tener todos los índices.


SELECCIONE la versión (a) : "PostgreSQL 9.3.14"
SELECCIONE postgis_version() : "2.1 USE_GEOS=1 USE_PROJ=1 USE_STATS=1"

Aquí están los índices tengo:

CREATE INDEX world_poi_idx4
  ON public.poi
  USING gist
  ((geometry::geography));

CREATE INDEX world_poi_new_idx3
  ON public.poi
  USING gist
  (geometry);

 CREATE INDEX world_poi_idx1
  ON public.poi
  USING btree
  (category);

Aquí están los resultados de explicar a analizar (por ejemplo de un solo caso, los resultados son diferentes en otros casos, esto es sólo para dar una idea):

Cuando la categoría de índice está presente: https://explain.depesz.com/s/iZWj

Cuando la categoría de índice no está presente: https://explain.depesz.com/s/0WH

1voto

jlehenbauer Puntos 7749
  • ¿Por qué no alterar la geometría en la geografía, asumiendo que no tienen para reproyectar,

    ALTER TABLE poi ALTER COLUMN geometry RENAME TO geog;
    ALTER TABLE poi ALTER COLUMN geog TYPE geography;
    

Gracias por la consulta, ahora puedo ver lo que estás haciendo.

  1. Vamos a optimizar el ST_SetSRID(ST_MakePoint()) y ver si eso ayuda a que el planificador
  2. Vamos a cambiar de arriba ST_Distance_Sphere a ST_Distance. Usted ya tiene un índice en el elenco de todos modos .. trate de ambos

Intente esto..

SELECT ST_X(geometry) as long2,
  ST_Y(geometry) AS lat2,
  ST_Distance( geometry::geography, point.p, false ) AS distance,
FROM ( VALUES
  (ST_SetSRID(
    ST_MakePoint(-118.478255,34.303046999999999),
    4326
  )::geography)
) AS point(p)
CROSS JOIN poi
WHERE category = 10980400
  AND ST_DWithin( point.p, geometry, 80467.2, false )
ORDER BY distance
LIMIT 10;

Además de la optimización de la con <->

También, a partir de la documentación en <-> usted puede ver este método sugerido.

9.5+ con KNN <->

Sólo lo estás haciendo ST_Distance() en 10 puntos con este método. Me volvería a calcular en el sphereoid y no de la esfera.

SELECT ST_X(geometry) as long2,
  ST_Y(geometry) AS lat2,
  ST_Distance( geometry::geography, point.p, false ) AS distance,
FROM ( VALUES
  (ST_SetSRID(
    ST_MakePoint(-118.478255,34.303046999999999),
    4326
  )::geography)
) AS point(p)
CROSS JOIN poi
WHERE category = 10980400
  AND ST_DWithin( point.p, geometry, 80467.2, false )
ORDER BY geometry::geography <-> point.p
LIMIT 10;

Pre-9.5 híbrido hack de optimización

Sólo lo estás haciendo ST_Distance() sobre 100 puntos con este método. Me volvería a calcular sobre el esferoide y no de la esfera.

WITH t AS (
  SELECT ST_X(geometry) as long2,
    ST_Y(geometry) AS lat2,
    ST_Distance( geometry::geography, point.p, false ) AS distance,
  FROM ( VALUES
    (ST_SetSRID(
      ST_MakePoint(-118.478255,34.303046999999999),
      4326
    )::geography)
  ) AS point(p)
  CROSS JOIN poi
  WHERE category = 10980400
    AND ST_DWithin( point.p, geometry, 80467.2, false )
  ORDER BY geometry::geography <-> point.p
  LIMIT 100
)
SELECT * FROM t
ORDER BY distance
LIMIT 10;

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