在我的Rails应用程序中,我具有允许查找与当前登录用户最接近的用户的功能。我为此使用了Geocoder gem。在用户模型中,我具有如下范围:
scope :close_to, -> (user:, distance:) {
where.not(id: user.id)
.near([user.latitude, user.longitude], distance)
}
这非常有效,但是对于大量用户而言却很慢。当我调用此作用域时,它将生成以下sql查询:
SELECT users.*, 6371.0 * 2 * ASIN(SQRT(POWER(SIN((48.471645 - users.latitude) * PI() / 180 / 2), 2) + COS(48.471645 * PI() / 180) * COS(users.latitude * PI() / 180) * POWER(SIN((-83.102801 - users.longitude) * PI() / 180 / 2), 2))) AS distance, MOD(CAST((ATAN2( ((users.longitude - -83.102801) / 57.2957795), ((users.latitude - 48.471645) / 57.2957795)) * 57.2957795) + 360 AS decimal), 360) AS bearing FROM "users" WHERE ("users"."id" != 43362) AND (users.latitude BETWEEN 39.4784289408127 AND 57.46486105918731 AND users.longitude BETWEEN -96.6674214298497 AND -69.5381805701503 AND (6371.0 * 2 * ASIN(SQRT(POWER(SIN((48.471645 - users.latitude) * PI() / 180 / 2), 2) + COS(48.471645 * PI() / 180) * COS(users.latitude * PI() / 180) * POWER(SIN((-83.102801 - users.longitude) * PI() / 180 / 2), 2)))) BETWEEN 0.0 AND 1000) ORDER BY distance ASC;
我正在尝试为此创建索引,但它们不起作用。我正在尝试以下组合:
1.
add_index :users, [:id, :latitude]
add_index :users, [:id, :longitude]
2. add_index :users, [:id, :latitude, :longitude]
3. add_index :users, [:latitude]
add_index :users, [:longitude]
4. add_index :users, [:id, :latitude]
我应该如何添加索引以加快此查询的速度?
编辑:我忘记添加我的纬度和经度列是小数。
此查询的ANALYZE返回类似以下内容:
Sort (cost=7141.66..7142.14 rows=191 width=327) (actual time=575.995..585.543 rows=36598 loops=1)
Sort Key: ((12742::double precision * asin(sqrt((power(sin((((((48.471645 - latitude))::double precision * 3.14159265358979::double precision) / 180::double precision) / 2::double precision)), 2::double precision) + ((0.662990616338754::double precision * cos((((latitude)::double precision * 3.14159265358979::double precision) / 180::double precision))) * power(sin(((((((-83.102801) - longitude))::double precision * 3.14159265358979::double precision) / 180::double precision) / 2::double precision)), 2::double precision)))))))
Sort Method: external merge Disk: 4672kB
-> Seq Scan on users (cost=0.00..7134.43 rows=191 width=327) (actual time=0.381..517.615 rows=36598 loops=1)
Filter: ((id <> 43362) AND (latitude >= 39.4784289408127) AND (latitude <= 57.46486105918731) AND (longitude >= (-96.6674214298497)) AND (longitude <= (-69.5381805701503)) AND ((12742::double precision * asin(sqrt((power(sin((((((48.471645 - latitude))::double precision * 3.14159265358979::double precision) / 180::double precision) / 2::double precision)), 2::double precision) + ((0.662990616338754::double precision * cos((((latitude)::double precision * 3.14159265358979::double precision) / 180::double precision))) * power(sin(((((((-83.102801) - longitude))::double precision * 3.14159265358979::double precision) / 180::double precision) / 2::double precision)), 2::double precision)))))) >= 0::double precision) AND ((12742::double precision * asin(sqrt((power(sin((((((48.471645 - latitude))::double precision * 3.14159265358979::double precision) / 180::double precision) / 2::double precision)), 2::double precision) + ((0.662990616338754::double precision * cos((((latitude)::double precision * 3.14159265358979::double precision) / 180::double precision))) * power(sin(((((((-83.102801) - longitude))::double precision * 3.14159265358979::double precision) / 180::double precision) / 2::double precision)), 2::double precision)))))) <= 1000::double precision))
Rows Removed by Filter: 6756
Planning time: 1.041 ms
Execution time: 587.695 ms
(8 rows)
编辑2:
我注意到postgresql使用了我的
add_index :users, [:latitude, :longitude]
仅当我键入小距离ex时。用户在10公里左右。
速度降低可能是由于数学运算而不是由于获取表数据引起的。您的部分条件不是针对记录字段,而是针对其他记录上的数学运算结果,因此它变为O(N 2)。
Postgres不使用索引而是选择Seq扫描的原因是因为它决定查询时必须提取大多数表记录。当要获取表中的大多数记录时,索引可能不会带来太多好处(如果有的话)。
为了加快速度,您应该考虑使用空间索引和基于PostGis的邻近搜索,或者使用Elasticsearch
with Geo Distance
Query
。
我已经在我的windows计算机上安装了logstash和elasticSearch,配置如下(根据配置,它在1分钟内轮询客户表中的记录) #1 Logstash配置文件加载客户表数据并将其索引为Logstash-config.conf #2用数据库创建包含一些记录的表 #4点击get API 4.1:不返回任何记录http://localhost:9200/customer_index/_sea
操作步骤: ①以编辑状态进入地图,点击左侧图例面板中要使用的图层,所选图层的边缘显示为蓝色,表示新添加的标注将绘制在此图层上。 ②点击地图右上方工具栏上的"搜索"图标。 ③弹出搜索框。 ④在搜索框内输入关键字(如:天安门)后,点击搜索/回车。 ⑤在左边的搜索结果列表框中选择正确的地点,点击信息窗上的"添加点"按钮。 ⑥点击"完成"添加记录成功。 操作动图: [查看原图]
如何在android Studio中快速搜索一个类文件或整个资源文件?
我面临毕加索无法快速加载图像的问题。 有3个显示左、中、右图像。在快进/后退时,对于给定的时间点,选择左、中、右并显示在三个框中。 这是初始化。缓存是100MB以及99MB的 窗口移动的图像数是3000。所以我将图像预加载为 平均图像大小为10KB-320x180,因此达到35MB,小于99MB。 当快速循环工作时,许多图像是(来自)和(来自),但在几个快速循环之后,3个图像冻结或变得非常慢。此时
问题内容: 应用程序如何执行邻近搜索?例如,用户输入邮政编码,然后应用程序按距离排序列出20英里内的所有企业。 我想在PHP和MySQL中构建类似的东西。这种方法正确吗? 获取我感兴趣的位置的地址并将其存储在数据库中 使用Google的地理编码服务对所有地址进行地理编码 编写包含Haversine公式的数据库查询以进行邻近搜索和排序 这个可以吗?在第3步中,我将计算每个查询的接近度。有一个PROX
我有大量相同类型的实体,每个实体都有大量属性,并且我只有以下两种选择来存储它们: 将每个项存储在索引中并执行多索引搜索 将所有enties存储在单个索引中,并且只搜索1个索引。 一般而言,我想要一个时间复杂度之间的比较搜索“N”实体与“M”特征在上述每一种情况!