我有桌子看起来像:
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
问题是第二个查询返回结果但速度要慢得多,而不是第一个查询返回结果但速度非常快(索引搜索)。我当然喜欢两者的混合物。毫不奇怪,我想要结果并且尽可能快。
您的坐标对可能已反转。请记住,ST_MakePoint
期望x,y,而不是y,x。要么你在也门的某个地方有你的观点 - POINT(46.0299536240291 14.4783371228873)
:
或者在斯洛文尼亚 - POINT(14.4783371228873 46.0299536240291)
:
地理列或ST_MakePoint
上的坐标对都是反转的。
此外,地理类型列中的地理函数(在查询中用作Geography(location)
)是多余的。您似乎也尝试将x,y存储在单独的列中,然后在地理列中插入相同的值。如果可以的话,摆脱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)
location
和你创造的点有lat-long倒置。可以理解的是,这两个查询需要不同的时间(使用索引来过滤掉所有行而不是计算/排序确切的距离)
select st_astext('0101000020E610000003CD3585D50347400287769AE8F42C40');
st_astext
------------------------------------------
POINT(46.0299536240291 14.4783371228873)