Всем привет!
Под капотом Django2.2, PostgreSql12, Postgis2.5 и есть (допустим) такая модель:
from django.contrib.gis.db import models
from django.contrib.postgres.indexes import GistIndex
class Poi(models.Model):
class Meta:
indexes = [ GistIndex(fields=['geom']) ]
geom = models.PointField(srid=32767, dim=3, unique=True, db_index=True)
в БД около 1М точек,
требуется найти N точек ближайших к заданной. решается подобное, в общем, не сложно:
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.geos import Point
POI = 'Point(0 0)'
location = Point.from_ewkt('SRID=32767;' + POI)
queryset = Poi.objects.annotate(distance=Distance('geom', location)).order_by('distance')[:100]
однако explain analyze queryset'а
SELECT *, ST_Distance(poi.geom, ST_GeomFromEWKB('\001\001\000\000 \377\177\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000'::bytea)) AS "distance" FROM poi ORDER BY "distance" ASC LIMIT 100
пишет грусть-тоску-печаль...
-> Parallel Seq Scan on poi (cost=0.00..61176.72 rows=566341 width=668) (actual time=1.049..449.942 rows=481390 loops=2)
Planning Time: 0.238 ms
Execution Time: 724.899 ms
собственно вопрос:
как в наш любимый ORM переписать это:
SELECT * FROM poi ORDER BY geom <-> 'SRID=32767;Point(0 0)'::geometry LIMIT 100
который, как и хотелось бы, отрабатывает по индексу:
-> Index Scan using poi_geom_gist on poi (cost=0.29..48529.07 rows=962779 width=668) (actual time=0.316..0.755 rows=100 loops=1)"
Order By: (geom <-> '0101000020FF7F000000000000000000000000000000000000'::geometry)
Planning Time: 0.169 ms
Execution Time: 0.821 ms
Спасибо!