Trouver la ligne la plus proche avec 2 points à l'aide de PostGIS?

9

J'ai une table t qui contient une colonne line_positionsde type ligne. Compte tenu de 2 points, je veux trouver la ligne la plus proche suffisamment proche (moins de 10 km) et qui ne passe pas trop près d'un point que je veux éviter (20 km minimum). Actuellement j'utilise

SELECT t.*
FROM path t
WHERE
  ST_DWithin(ST_GeographyFromText('Point(69.835 22.596)'), t.line_positions, 10000, FALSE)  AND
  ST_DWithin(ST_GeographyFromText('Point(69.856 22.519)'), t.line_positions, 10000, false) AND
  NOT ST_DWithin(ST_GeographyFromText('Point(-79.804 9.141)'), t.line_positions, 20000, false)
ORDER BY
  ST_Distance(ST_GeographyFromText('Point(69.835 22.576)'), t.line_positions, false) +
  ST_Distance(ST_GeographyFromText('Point(69.856 22.519)'), t.line_positions, false)
  ASC
LIMIT 1

Il y a un index gist ix_path_line_positionssur la colonne line_positions.

Cela fonctionne mais lentement, entre 3s et 30s pour seulement 100000 lignes en t.

expliquer analyser donne:

Limit  (cost=9.95..9.95 rows=1 width=1432) (actual time=21729.253..21729.254 rows=1 loops=1)
   ->  Sort  (cost=9.95..9.95 rows=1 width=1432) (actual time=21729.251..21729.251 rows=1 loops=1)
         Sort Key: ((_st_distance('0101000020E61000003D0AD7A370755140FA7E6ABC74933640'::geography, line_positions, '0'::double precision, false) + _st_distance('0101000020E6100000105839B4C8765140BE9F1A2FDD843640'::geography, line_positions, '0'::double precision, false)))
         Sort Method: top-N heapsort  Memory: 26kB"
         ->  Index Scan using ix_path_line_positions on path t  (cost=0.28..9.94 rows=1 width=1432) (actual time=93.490..21710.562 rows=690 loops=1)
           Index Cond: ((line_positions && '0101000020E61000003D0AD7A3707551407F6ABC7493983640'::geography) AND (line_positions && '0101000020E6100000105839B4C8765140BE9F1A2FDD843640'::geography))
           Filter: (('0101000020E61000003D0AD7A3707551407F6ABC7493983640'::geography && _st_expand(line_positions, '10000'::double precision)) AND ('0101000020E6100000105839B4C8765140BE9F1A2FDD843640'::geography && _st_expand(line_positions, '10000'::double precision)) AND _st_dwithin('0101000020E61000003D0AD7A3707551407F6ABC7493983640'::geography, line_positions, '10000'::double precision, false) AND _st_dwithin('0101000020E6100000105839B4C8765140BE9F1A2FDD843640'::geography, line_positions, '10000'::double precision, false) AND ((NOT ('0101000020E6100000FA7E6ABC74F353C0D578E92631482240'::geography && _st_expand(line_positions, '20000'::double precision))) OR (NOT (line_positions && '0101000020E6100000FA7E6ABC74F353C0D578E92631482240'::geography)) OR (NOT _st_dwithin('0101000020E6100000FA7E6ABC74F353C0D578E92631482240'::geography, line_positions, '20000'::double precision, false))))
           Rows Removed by Filter: 15365
Planning time: 0.491 ms
Execution time: 21729.321 ms

Comment pourrais-je l'améliorer? Utiliser à la place le calcul de la géométrie (mais ma trace peut s'étendre sur plusieurs milliers de kilomètres, les distances calculées seront-elles correctes)? En utilisant <-> l'opérateur KNN (mais comme je commande sur la somme de 2 distances, il ne semble pas utiliser l'index gist de toute façon)?

Go4It
la source
Vous pouvez essayer d'augmenter le paramètre work_mem avant d'exécuter le code. Par exempleSET work_mem TO '200MB';
Yaroslav

Réponses:

1

Les deux points donnés sont-ils toujours à moins de 10 km l'un de l'autre? Si c'est le cas, vous pouvez essayer de faire des deux points une ligne et effectuer un ST_DWithin au lieu de deux. Cela peut améliorer légèrement les choses.

SELECT t.*
FROM path t
WHERE
  ST_DWithin(ST_GeomFromText('LINESTRING(69.835 22.596,69.856 22.519)'), t.line_positions, 10000, FALSE)  
  NOT ST_DWithin(ST_GeographyFromText('Point(-79.804 9.141)'), t.line_positions, 20000, false)
ORDER BY
  ST_Distance(ST_GeographyFromText('Point(69.835 22.576)'), t.line_positions, false) +
  ST_Distance(ST_GeographyFromText('Point(69.856 22.519)'), t.line_positions, false)
  ASC
LIMIT 1
user92055
la source
Non, les 2 points ne sont pas à moins de 10 km l'un de l'autre, ils peuvent être à mille kilomètres. La contrainte est que les deux sont à moins de 10 km de la ligne, mais cela pourrait vraiment être loin car les lignes s'étendent sur des milliers de km.
Go4It