postgresql - Postgres - 全表扫描太慢 - 未使用索引

标签 postgresql optimization

我在 postgres 数据库中有一个包含许多列的表,其中我有:

n_store_object_id     integer,
n_latitude            decimal,
n_longitude           decimal

该表目前大约有 250,000 行。

我需要找到距离给定位置固定距离内具有非空 store_object_id 的记录。对于距离计算,我有以下功能:

CREATE OR REPLACE FUNCTION fn_geo_distance(numeric, numeric, numeric, numeric)
  RETURNS numeric AS
$BODY$
declare
    lat1d       ALIAS for $1;
    lon1d       ALIAS for $2;
    lat2d       ALIAS for $3;
    lon2d       ALIAS for $4;

    lat1        DECIMAL := lat1d / 57.29577951;
    lon1        DECIMAL := lon1d / 57.29577951;
    lat2        DECIMAL := lat2d / 57.29577951;
    lon2        DECIMAL := lon2d / 57.29577951;
begin
    return 3963.0 * acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1));
end;$BODY$
  LANGUAGE plpgsql IMMUTABLE;

现在,我需要的查询很简单:

select *
  from objects
 where n_store_object_id is not null
   and fn_geo_distance(51.5, 0, n_latitude, n_longitude) <= 20

这需要相当长的时间 - 当我“解释”这个查询时,我可以看到全表扫描。很公平。所以我在这三列上创建了一个索引:

create index idx_object_location on objects(n_store_object_id, n_latitude, n_longitude)

我重新运行上面的查询 - 仍然需要很长时间。 “解释”表明新创建的索引没有被使用。我错过了什么吗?为什么不使用它,如何强制引擎使用它?哦,首先,这个索引有帮助吗?

谢谢!

最佳答案

您的索引按 ID 排序,然后是纬度,然后是经度。这无济于事,因为它无法找出要搜索的 ID 范围。

您不能使用传统的“btree”索引(postgres 和所有其他 sql 中的默认索引)很好地索引。如果您稍微考虑一下这个问题,就会发现大多数索引都是基于对事物进行排序(按数字或字母顺序)的。但你不能订购地理。您可以按照事物与一个点的距离排序,但当您移动该点时,有些事物会更近,有些会更远,因此顺序会发生变化。

最佳... 针对此问题创建了特殊索引。由于您使用的是 postgres,我建议您阅读 GiST。 http://postgis.net/docs/manual-2.0/using_postgis_dbmanagement.html (请谷歌搜索并点击此链接)。

这现在作为 postgres 的一部分包含在内,专为处理地理问题而设计。

或者…… 第二种解决方案是在数据上放置两个索引,一个纬度(仅)和一个对数(仅)。并如另一个答案中所述向查询添加最大和最小纬度和经度。 Postgres 可以同时使用两个索引来缩小范围。重要的是您使用两个单独的索引,而不是一个同时包含纬度和经度的索引。

关于postgresql - Postgres - 全表扫描太慢 - 未使用索引,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8448811/

相关文章:

python - sqlalchemy 在多个表上联接和排序

java - 带有 Hibernate 的 PostgreSQL 没有持久化我的实体

django - 在 x 分钟/小时后更新表

python - 异常 : @error: Max Equation Length in Gekko

algorithm - 检查 3 个变量是否都是唯一的熟练方法

mysql - Rails 4/postgresql 索引 - 我应该使用可以有无限多个值的日期时间列作为索引过滤器吗?

python - AdamW 的衰减学习率计划如何影响权重衰减参数?

algorithm - 为什么这些小型 D 程序的行为不同?

c - 在 C 中将 float 转换为处理器内部的 int

postgresql - 为什么 psql 不要求我输入密码来访问我刚刚为其创建密码的登录角色的 psql?