【问题标题】:Getting geography locations in radius获取半径中的地理位置
【发布时间】:2025-12-19 15:40:07
【问题描述】:

我的桌子看起来像:

CREATE TABLE public.places
    (
        id bigint DEFAULT nextval('places_id_seq'::regclass) PRIMARY KEY NOT NULL,
        lon numeric(18,13) DEFAULT NULL::numeric,
        lat numeric(18,13) DEFAULT NULL::numeric,
        location geography(Point,4326)
    );
    CREATE INDEX places_ll ON public.places (lon, lat);
    CREATE INDEX places_location_ix ON public.places (location);
    INSERT INTO public.places (id, lon, lat, location) VALUES (1, 14.4783371228873, 46.0299536240291, '0101000020E610000003CD3585D50347400287769AE8F42C40');

现在我不想通过查询找到附近的位置:

SELECT ST_Distance(Geography(ST_MakePoint(14.47859, 46.02998166)), location) as dist, lon, lat, location FROM places
WHERE ST_DWithin(Geography(ST_MakePoint(14.47859, 46.02998166)), Geography(location), 50) ORDER BY dist LIMIT 1;

我得到零结果。然后我尝试查询:

SELECT ST_Distance(Geography(ST_MakePoint(14.47859, 46.02998166)), ST_MakePoint(lon,lat)) as dist, lon, lat, location FROM places
WHERE ST_DWithin(Geography(ST_MakePoint(14.47859, 46.02998166)), Geography(ST_MakePoint(lon,lat)), 50) ORDER BY dist LIMIT 1;

我得到了一个结果:

14.4783371228873    46.0299536240291    0101000020E610000003CD3585D50347400287769AE8F42C40

问题是第二个查询返回结果但慢得多,而第一个查询不返回结果但非常快(索引搜索)。我当然想要两者的混合。毫不奇怪,我希望尽快取得成果。

【问题讨论】:

  • 不相关:为什么将 x,y 和地理位置放在同一张表中?
  • 不相关 - 如果您在地理/几何上创建索引,则创建 GIST 索引而不是 btree 索引 CREATE INDEX ON public.places using GIST(location); Btree 不适用于 ST_Dwithin 和其他函数
  • 您还可以从 geom 获取 lat 和 long 作为 st_x(location) 和 st_y(location) 。不要将 lon lat 用作单独的列,这是多余的。

标签: sql postgresql postgis


【解决方案1】:

您的坐标对可能是倒置的。请记住,ST_MakePoint 需要 x,y,而不是 y,x。要么你在也门的某个地方有你的观点 - POINT(46.0299536240291 14.4783371228873)

或者在斯洛文尼亚 - POINT(14.4783371228873 46.0299536240291):

地理列或ST_MakePoint 处的坐标对被反转。

此外,地理函数 - 在您的查询中用作 Geography(location) - 在 geography 类型列中是多余的。您似乎还尝试将 x,y 存储在单独的列中,然后在地理列中插入相同的值。如果可以的话,去掉 x,y 列,因为它们也是多余的...... geography 就足够了。

如果 x,y 是 46.02998166,14.47859 试试这个:

SELECT 
  ST_Distance(Geography(ST_MakePoint(46.02998166,14.47859)), location) AS dist, 
  lon, lat, ST_AsText(location) 
FROM places
WHERE 
  ST_DWithin(Geography(ST_MakePoint(46.02998166,14.47859)), 
  location, 50) ORDER BY dist LIMIT 1;

    dist     |       lon        |       lat        |                st_astext                 
-------------+------------------+------------------+------------------------------------------
 28.14204157 | 14.4783371228873 | 46.0299536240291 | POINT(46.0299536240291 14.4783371228873)

【讨论】:

  • 是的,我知道纬度/经度字段是多余的,因此将被删除。点在斯洛文尼亚。它接缝来自@Jim-Jones 的查询解决了我所有的问题。它是索引搜索并返回结果。所以谢谢你(和所有其他人)。
【解决方案2】:

location 和您创建的点的经纬度倒置。可以理解的是,这两个查询花费的时间不同(使用索引过滤掉所有行,而不是计算/排序确切的距离)

select st_astext('0101000020E610000003CD3585D50347400287769AE8F42C40');
                st_astext
------------------------------------------
 POINT(46.0299536240291 14.4783371228873)

【讨论】: