我的桌子看起来像:
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
问题是第二个查询返回结果,但是要慢得多,而第一个查询不返回结果,但是非常快(索引搜索)。当然,我想要两者的混合。毫不奇怪,我想要结果并且要尽可能快。
答案 0 :(得分:1)
您的坐标对可能已反转。请记住,ST_MakePoint
期望 x,y ,而不是 y,x 。您在也门的某个地方-POINT(46.0299536240291 14.4783371228873)
:
或者在斯洛文尼亚-POINT(14.4783371228873 46.0299536240291)
:
“地理”列或ST_MakePoint
处的坐标对都被反转。
此外,地理类型列中的地理功能(在查询中用作Geography(location)
)是多余的。似乎您还试图将 x,y 存储在单独的列中,然后在geography列中插入相同的值。如果可以的话,请除去 x,y 列,因为它们也是多余的... 地理位置就足够了。
如果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)
答案 1 :(得分:0)
location
和您创建的点经纬度倒置。可以理解的是,这两个查询花费的时间不同(使用索引来过滤所有行而不是计算/排序精确的距离)
select st_astext('0101000020E610000003CD3585D50347400287769AE8F42C40');
st_astext
------------------------------------------
POINT(46.0299536240291 14.4783371228873)