[postgis-tickets] [PostGIS] #3548: Slow queries with ST_DWithin and geography columns

PostGIS trac at osgeo.org
Mon May 9 09:53:04 PDT 2016


#3548: Slow queries with ST_DWithin and geography columns
----------------------------------+---------------------------
 Reporter:  rdallasgray           |      Owner:  pramsey
     Type:  defect                |     Status:  new
 Priority:  medium                |  Milestone:  PostGIS 2.2.3
Component:  postgis               |    Version:  2.1.x
 Keywords:  ST_DWithin geography  |
----------------------------------+---------------------------
 We noticed that a query to find points within a given distance of a line
 was running slowly. The points have SRID 4326 and are recorded with an
 indexed geography column.

 The culprit appears to be the filter step where `_st_dwithin` is run
 against each of the records returned by the index.

 We were able to work around the issue by introducing a second ST_DWithin
 condition which runs against an indexed geometry column (again SRID 4326).
 We set the distance parameter for this in a rough conversion of metres to
 degrees, allowing a large buffer to ensure we include all candidate
 points. This narrowed the field sufficiently and the query is now ~300%
 faster.

 Interestingly, the order of the two ST_DWithin queries matters. If we run
 the geographic query first, we have poor performance. If we run the
 geometric query first, we have the better performance.

 Attached are redacted queries and explain results.

 === QUERY 1 ===

 {{{
 SELECT COUNT(*) FROM "locations"
 WHERE (ST_DWithin(
   ST_SetSRID(ST_MakeLine(
   ARRAY[
     ST_MakePoint(2.1736, 41.38518) <... redacted, approx 200 points>
 ST_MakePoint(73.31681999999995, 55.05574999999999)
   ]
 )
 , 4326)::geography,
   locations.geog,
   5000,
   false
 )
 );
 }}}

 === EXPLAIN 1 ===

 {{{
  Aggregate  (cost=2.76..2.77 rows=1 width=0) (actual
 time=6501.755..6501.757 rows=1 loops=1)
    Buffers: shared hit=15542
    ->  Index Scan using index_locations_on_geog on locations
 (cost=0.28..2.76 rows=1 width=0) (actual time=8.016..6499.419 rows=1121
 loops=1)
          Index Cond: (geog && '01<...>40'::geography)
          Filter: (('01<...>40'::geography && _st_expand(geog, 5000::double
 precision)) AND _st_dwithin('01<...>40'::geography, geog, 5000::double
 precision, false))
          Rows Removed by Filter: 19213
          Buffers: shared hit=15542
  Total runtime: 6502.081 ms
 }}}

 === QUERY 2 ===

 {{{
 SELECT COUNT(*) FROM "locations"
 WHERE (ST_DWithin(
   ST_SetSRID(ST_MakeLine(
   ARRAY[
   ST_MakePoint(2.1736, 41.38518) <... redacted, approx 200 points>
 ST_MakePoint(73.31681999999995, 55.05574999999999)
   ]
 )
 , 4326)::geography,
   locations.geog,
   5000,
   false
 )
 AND (ST_DWithin(
   ST_SetSRID(ST_MakeLine(
   ARRAY[
   ST_MakePoint(2.1736, 41.38518) <... redacted, approx 200 points>
 ST_MakePoint(73.31681999999995, 55.05574999999999)
   ]
 )
 , 4326),
   locations.geom,
   0.26
 )
 )
 );
 }}}

 === EXPLAIN 2 ===

 {{{
  Aggregate  (cost=3.02..3.02 rows=1 width=0) (actual
 time=5976.269..5976.270 rows=1 loops=1)
    Buffers: shared hit=15468
    ->  Index Scan using index_locations_on_geog on locations
 (cost=0.28..3.01 rows=1 width=0) (actual time=5.942..5973.619 rows=1121
 loops=1)
          Index Cond: (geog && '01<...>40'::geography)
          Filter: ((geom &&
 '0103000020E6100000010000000500000075029A081B9EFE3F800EF3E50590444075029A081B9EFE3F8FC151F2EA484C406DEB6E9EEA6452408FC151F2EA484C406DEB6E9EEA645240800EF3E50590444075029A081B9EFE3F800EF3E505904440'::geometry)
 AND ('01<...>40'::geography && _st_expand(geog, 5000::double precision))
 AND ('01<...>40'::geometry && st_expand(geom, 0.26::double precision)) AND
 _st_dwithin('01<...>40'::geography, geog, 5000::double precision, false)
 AND _st_dwithin('01<...>40'::geometry, geom, 0.26::double precision))
          Rows Removed by Filter: 19213
          Buffers: shared hit=15468
  Total runtime: 5976.354 ms
 }}}

 === QUERY 3 ===

 {{{
 SELECT COUNT(*) FROM "locations"
 WHERE (ST_DWithin(
   ST_SetSRID(ST_MakeLine(
   ARRAY[
     ST_MakePoint(2.1736, 41.38518) <... redacted, approx 200 points>
 ST_MakePoint(73.31681999999995, 55.05574999999999)
   ]
 )
 , 4326),
   locations.geom,
   0.26
 )
 )
 AND (ST_DWithin(
   ST_SetSRID(ST_MakeLine(
   ARRAY[
     ST_MakePoint(2.1736, 41.38518) <... redacted, approx 200 points>
 ST_MakePoint(73.31681999999995, 55.05574999999999)
   ]
 )
 , 4326)::geography,
   locations.geog,
   5000,
   false
 )
 );
 }}}

 === EXPLAIN 3 ===

 {{{
  Aggregate  (cost=3.02..3.02 rows=1 width=0) (actual
 time=1308.285..1308.287 rows=1 loops=1)
    Buffers: shared hit=15468
    ->  Index Scan using index_locations_on_geog on locations
 (cost=0.28..3.01 rows=1 width=0) (actual time=1.917..1306.076 rows=1121
 loops=1)
          Index Cond: (geog && '01...40'::geography)
          Filter: ((geom &&
 '0103000020E6100000010000000500000075029A081B9EFE3F800EF3E50590444075029A081B9EFE3F8FC151F2EA484C406DEB6E9EEA6452408FC151F2EA484C406DEB6E9EEA645240800EF3E50590444075029A081B9EFE3F800EF3E505904440'::geometry)
 AND ('01...40'::geometry && st_expand(geom, 0.26::double precision)) AND
 ('01...40'::geography && _st_expand(geog, 5000::double precision)) AND
 _st_dwithin('01...40'::geometry, geom, 0.26::double precision) AND
 _st_dwithin('01...40'::geography, geog, 5000::double precision, false))
          Rows Removed by Filter: 19213
          Buffers: shared hit=15468
  Total runtime: 1308.386 ms
 }}}

--
Ticket URL: <https://trac.osgeo.org/postgis/ticket/3548>
PostGIS <http://trac.osgeo.org/postgis/>
The PostGIS Trac is used for bug, enhancement & task tracking, a user and developer wiki, and a view into the subversion code repository of PostGIS project.


More information about the postgis-tickets mailing list