假设我有以下数据模型
Person(models.Model):
id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=50)
location = models.PointField(srid=4326)
假设我有一个应用程序对此django后端进行查询,此应用程序的唯一目的是返回从最近到最远的注册用户的(分页)列表。
目前我还记得这个问题:
# here we are obtaining all users in ordered form
current_location = me.location
people = Person.objects.distance(current_location).order_by('distance')
# here we are obtaining the first X through pagination
start_index = a
end_index = b
people = people[a:b]
虽然这有效,但它并不像我想的那么快。
我对此查询的速度有些担心。如果表格很大(100万+)那么数据库(Postgres SQL w / PostGIS)在执行{{1}之前不必测量数据库中current_location
和每个location
之间的距离随后有100万行吗?
有人可以建议如何以有效的方式正确地返回按距离排序的附近用户吗?
答案 0 :(得分:3)
如果你想按距离对该表上的每个条目进行排序,那么它将如预期的那样缓慢,并且没有什么可以做的(我知道这个时间点和我的知识。)!
通过执行以下步骤并做出一些假设,您可以提高计算效率:
在表格中启用spatial indexing。要在GeoDjango中执行此操作,请按照the doc instructions并使其适合您的模型:
请注意
在PostGIS中,ST_Distance_Sphere不限制执行查询的地理距离的几何类型。 [4]但是,这些查询可能需要很长时间,因为必须为查询中的每一行动态计算大圆距离。这是因为无法使用传统几何字段的空间索引。
要在WGS84距离查询上获得更好的性能,请考虑在数据库中使用geography columns,因为它们能够在距离查询中使用其空间索引。您可以通过在字段定义中设置
geography=True
来告知GeoDjango使用地理列。
现在,您可以使用一些逻辑约束来缩小查询范围:
Ex:我的用户不会寻找离他当前位置超过50公里的人。
使用dwithin
空间查找缩小搜索范围,利用上面提到的spatial indexing,因此它非常快。
最后在其余行上应用distance
订单。
最终查询可能如下所示:
current_location = me.location
people = People.objects.filter(
location__dwithin=(current_location, D(km=50))
).annotate(
distance=Distance('location', current_location)
).order_by('distance')
P.S:不是创建自定义分页尝试,而是使用为django视图提供的分页方法更有效:
或者您可以使用Django Rest Framework并使用它的分页: