添加索引以加快地理编码器附近的搜索速度

2024-01-02

在我的 Rails 应用程序中,我具有允许查找最接近当前登录用户的用户的功能。我正在为此使用地理编码器 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)

EDIT 2:

我注意到 postgresql 使用我的

add_index :users, [:latitude, :longitude]

仅当我输入短距离时。用户在近10公里范围内。


The slowdown is likely caused by math operations and not by fetching table data. Part of your criteria is not against record fields but against the outcome of the math operation on other records so it is becoming an O(N2).

Postgres之所以不使用索引而选择Seq扫描,是因为它决定查询时必须取出大部分表记录。当要获取表中的大多数记录时,索引可能不会带来太多好处(如果有的话)。

为了加快速度,您应该考虑使用空间索引和基于邻近区域的搜索PostGis http://postgis.net/或者,Elasticsearch 与地理距离查询 https://www.elastic.co/guide/en/elasticsearch/reference/5.x/query-dsl-geo-distance-query.html.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

添加索引以加快地理编码器附近的搜索速度 的相关文章

  • 如何部署“SQL Server Express + EF”应用程序

    这是我第一次部署使用 SQL Server Express 数据库的应用程序 我首先使用实体 框架模型来联系数据库 我使用 Install Shield 创建了一个安装向导来安装应用程序 这些是我在目标计算机中安装应用程序所执行的步骤 安装
  • 如何获取自定义订单的结果? [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 代替ASC or DESC 我希望我的查询结果采用特定的自定义顺序 例如 如果我想要的结果不是 A B C D 而是 P A L H 该怎么
  • SELECT NULL、*、NULL、NULL 中令人困惑的 SQL 错误

    的背景我试图解决第四个现实任务 https www hackthissite org playlevel 4 在 hackthissite org 中 无法确切地弄清楚我应该在 URL 中注入什么 SQL 来检索电子邮件列表 浪费了几个小时
  • Heroku 没有更新 Rails 应用程序的 CSS

    我在 heroku 上更新 Rails 应用程序时遇到问题 我已经启动了我的应用程序 但我尝试更改 public stylesheets 中的 application css 文件 但每当我尝试推送到 heroku 时 CSS 都不会更改
  • Rails 3.2 防止使用错误保存对象

    我有一个 ActiveRecord 对象 我想阻止它被保存 而不对模型进行永久验证 你曾经可以使用做这样的事情errors add但它看起来不再有效了 user User last user errors add name name doe
  • 如何测试(rspec)耗时太长的 http 请求?

    如果 rspec 请求花费的时间太长 如何测试行为 我正在考虑使用线程来模拟这个 describe Test do it should timeout if the request takes too long do lambda thre
  • 加载“mysql2”Active Record 适配器时出错

    我正在尝试升级我的应用程序 这是我在部署应用程序时遇到的错误 加载 mysql2 Active Record 适配器时出错 缺少它所依赖的宝石 无法激活mysql2 0 4 4 已经激活mysql2 0 3 21 确保所有依赖项都添加到 G
  • 如何让 Redis 在 Heroku 上启动?

    我已经添加了RedistogoHeroku 上的 nano 插件 我已经在控制台中成功测试了它 但是 当我的应用程序尝试连接 Redis 时 出现以下错误 Heroku 日志文件 2011 10 12T08 19 50 00 00 app
  • 与 iexact 一起使用时,Django get_or_create 无法设置字段

    我想用name iexact with get or create尽可能避免用户输入字段的重复 我的提供者模型有一个名称字段 我在其中使用get or create 查找工作正常 但在第一次创建实例时 如下面的 p1 Timber 示例 名
  • Big Query - 将数组/json 对象转置为列

    这个问题是这两个问题的延续 Bigquery 将数组转置为列 https stackoverflow com q 64346504 7463780 大查询 将特定字段转置为列 https stackoverflow com q 643983
  • 如何获取日期时间字段的 UTC?

    我正在使用 MySQL 5 并且正在尝试将日期时间字段转换为 UTC TIMESTAMP 这是我所拥有的 但它不起作用 并且不确定我是否可以做到这一点 但有人可以告诉我我做错了什么吗 谢谢 我已经尝试过这个 SELECT UTC TIMES
  • 将扁平树解析为非扁平树的算法

    我有以下扁平树 id name parent id is directory 50 app 0 1 31 controllers 50 1 11 application controller rb 31 0 46 models 50 1 1
  • 如何将逗号分隔的列值与另一个表作为行连接

    我试图通过首先转换我正在成功执行的 SupplierId 列中的逗号分隔值来连接两个表 然而 当我尝试通过外键 DCLink 加入另一个带有供应商名称的表 Vendors 时 问题就出现了 这就是我的意思 原始表的 select 语句 SE
  • Oracle SQL 分析查询 - 类似递归电子表格的运行总计

    我有以下数据 由A值 排序依据MM 月 The B列计算为GREATEST current value of A previous value of B 0 以类似电子表格的方式 我怎样才能计算B使用 SQL 查询 我尝试使用分析函数 但未
  • 在 MySQL 中将值设置为 NULL

    我想要一个值被设置为NULL如果我提交的表单中的文本框中没有输入任何内容 我怎样才能做到这一点 我试过插入 NULL 但这只是添加了这个词NULL进入现场 我不确定我应该为此提供什么代码 我只是编写一个 UPDATE 查询 不要放NULL更
  • 在查询中创建临时变量

    我希望能够在查询中创建一个临时变量 而不是存储过程或函数 它不需要声明和设置 这样我在调用它时就不需要传递查询参数 正在努力朝这个方向努力 Select field1 tempvariable 2 2 newlycreatedfield t
  • 同一表中同一列的 SQL 完全外连接

    这可能更多的是一个设计问题 但我希望这在没有太多巫术的情况下是可能的 假设我有一个这样的表 SELECT FROM stuff id grp 1 a 2 a 3 a 1 b 2 b 4 b 我想要得到这样的东西 ID 按列分组 a id b
  • 使用 Carrierwave 上传到 S3 时获取 mp3 持续时间

    我正在编写一个应用程序 它基本上是一个音乐平台 我想通过其元数据获取 mp3 的持续时间 并将其保存在表中 然后再将其上传到 S3 我使用载波和雾宝石的组合来上传 提取 mp3 元数据以保存到数据库的推荐方法是什么 有一个用于此类操作的 g
  • 在 Rails 中使用 gem 时,“无法删除 Object::ClassMethods”源于什么?

    我在安装 gems 时经常遇到这样的问题 有谁知道这源于什么 我见过几个不同的案例 但仍然不知道到底是什么原因造成的 sudo rake gems install trace in u app releases 20100213003957
  • 如何确定在 Postgres 中使用什么类型的索引?

    我有一个 Postgres 数据库 其中有 2 列不是主键 也不能是主键 但进行了大量搜索 并与其他表中的 2 列进行比较 我相信这是向我的表添加索引的完美案例 我以前从未在数据库上使用过索引 所以我正在尝试学习执行此操作的正确方法 我了解

随机推荐