6

I am using PostgreSQL and PostGIS to handle geocoordinates in a table. How to create a spatial index on the GEOMETRY(POINT) type field to increase the performance of the distance-based ST_DWithin query?

I am using migrations to create indexes.

Aayush Taneja
  • 511
  • 7
  • 18
  • For Googlers who might be interested in the built-in PostgreSQL GIST rather than the external PostGIS extension: https://stackoverflow.com/questions/28292198/how-to-port-simple-spatial-index-using-sqlite-r-trees-to-postgres – Ciro Santilli OurBigBook.com Jul 13 '23 at 19:47

1 Answers1

9

For geometry it is recommended to use a gist index, e.g.

CREATE INDEX idx_any_label ON mytable USING gist (geom_column);

Data sample (50k random points):

CREATE TABLE t (geom geometry(point,4326));
INSERT INTO t 
SELECT ('SRID=4326;POINT('||floor(random() * 50)||' ' ||floor(random() * 50) ||')')
FROM generate_series(1,50000);

Query plan without an index:

EXPLAIN ANALYSE
SELECT * FROM t
WHERE ST_DWithin('SRID=4326;POINT(1 1)',geom,1);
    
 Seq Scan on t  (cost=0.00..1252068.48 rows=5 width=32) (actual time=122.091..144.137 rows=98 loops=1)
   Filter: st_dwithin('0101000020E6100000000000000000F03F000000000000F03F'::geometry, geom, '1'::double precision)
   Rows Removed by Filter: 49902
 Planning Time: 0.083 ms
 JIT:
   Functions: 2
   Options: Inlining true, Optimization true, Expressions true, Deforming true
   Timing: Generation 0.387 ms, Inlining 83.228 ms, Optimization 30.947 ms, Emission 7.626 ms, Total 122.187 ms
 Execution Time: 186.107 ms

Query plan with a gist index

CREATE INDEX idx_t_geom ON t USING gist (geom);

EXPLAIN ANALYSE
SELECT * FROM t
WHERE ST_DWithin('SRID=4326;POINT(1 1)',geom,1);
                                                           QUERY PLAN                                                           
--------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on t  (cost=4.98..2119.16 rows=5 width=32) (actual time=0.086..0.367 rows=98 loops=1)
   Filter: st_dwithin('0101000020E6100000000000000000F03F000000000000F03F'::geometry, geom, '1'::double precision)
   Rows Removed by Filter: 83
   Heap Blocks: exact=139
   ->  Bitmap Index Scan on idx_t_geom  (cost=0.00..4.98 rows=77 width=0) (actual time=0.063..0.064 rows=181 loops=1)
         Index Cond: (geom && st_expand('0101000020E6100000000000000000F03F000000000000F03F'::geometry, '1'::double precision))
 Planning Time: 0.291 ms
 Execution Time: 2.237 ms

Demo: db<>fiddle

Jim Jones
  • 18,404
  • 3
  • 35
  • 44
  • 1
    Is there a way to create this index without executing raw SQL commands? Any Sequelize function? – Aayush Taneja Jun 02 '21 at 12:53
  • 2
    I'm not very familiar with sequelize, but I am pretty sure it is possible to either execute ddl statements such as create index. Can't you run this stamentet yourself directly in the database? It is really short and only has to be fired once. – Jim Jones Jun 02 '21 at 13:03