我是 PostgreSQL 和 PostGIS 的新手。我想在 PostgreSQL 9.1.1 数据库表中存储纬度和经度值。我将计算两点之间的距离,使用这个位置值找到更近的点。
我应该为纬度和经度使用哪种数据类型?
您可以使用数据类型 point
- 结合可以是您的纬度/经度的 (x,y)
。占用 16 个字节:内部有 2 个 float8
数字。
或者将其设为 float
类型的两列(= float8
或 double precision
)。每个 8 个字节。
或 real
(= float4
),如果不需要额外的精度。每个 4 个字节。
如果您需要绝对精度,甚至可以使用 numeric
。每组 4 位数字 2 个字节,加上 3 - 8 个字节的开销。
阅读有关 numeric types 和 geometric types 的精美手册。
geometry
和 geography
数据类型由附加模块 PostGIS 提供,并占据表中的 一个 列。每个点占用 32 个字节。那里有一些额外的开销,比如 SRID。这些类型存储 (long/lat),而不是 (lat/long)。
开始阅读 PostGIS manual here。
在 PostGIS 中,对于具有纬度和经度的点,存在地理数据类型。
要添加列:
alter table your_table add column geog geography;
要插入数据:
insert into your_table (geog) values ('SRID=4326;POINT(longitude latitude)');
4326 是空间参考 ID,表示它的数据以经度和纬度为单位,与 GPS 相同。更多信息:http://epsg.io/4326
顺序是经度,纬度 - 因此,如果将其绘制为地图,则为 (x, y)。
要找到最近点,您首先需要创建空间索引:
create index on your_table using gist (geog);
然后请求,比如说,最接近给定点的 5:
select *
from your_table
order by geog <-> 'SRID=4326;POINT(lon lat)'
limit 5;
在 PostGIS 中,几何比地理(圆形地球模型)更受欢迎,因为计算更简单,因此速度更快。它还具有更多可用功能,但在很长的距离上不太准确。
将 CSV 经纬度字段导入 DECIMAL(10,6)
列。 6 位是 10 厘米精度,对于大多数用例来说应该足够了。然后将您导入的数据转换为正确的 SRID
错误的方法!
/* try what seems the obvious solution */
DROP TABLE IF EXISTS public.test_geom_bad;
-- Big Ben, London
SELECT ST_SetSRID(ST_MakePoint(-0.116773, 51.510357),4326) AS geom
INTO public.test_geom_bad;
正确的方式
/* add the necessary CAST to make it work */
DROP TABLE IF EXISTS public.test_geom_correct;
SELECT ST_SetSRID(ST_MakePoint(-0.116773, 51.510357),4326)::geometry(Geometry, 4326) AS geom
INTO public.test_geom_correct;
验证 SRID 不为零!
/* now observe the incorrect SRID 0 */
SELECT * FROM public.geometry_columns
WHERE f_table_name IN ('test_geom_bad','test_geom_correct');
使用 WKT 查看器验证 long lat 参数的顺序,然后
SELECT ST_AsEWKT(geom) FROM public.test_geom_correct
然后索引它以获得最佳性能
CREATE INDEX idx_target_table_geom_gist
ON target_table USING gist(geom);
select st_point(12.0, 42.0)::geometry(Geometry, 4326)
给出错误:几何 SRID (0) 与列 SRID (4326) 不匹配,但 select ST_SetSRID(ST_Point(12.0, 42.0),4326)
有效¯_(ツ)_/¯
如果您不需要 PostGIS 提供的所有功能,Postgres(现在)提供了一个名为 earthdistance 的扩展模块。它根据您对距离计算的准确性需求使用 point 或 cube 数据类型。
您现在可以使用 earth_box 函数来 - 例如 - 查询某个位置一定距离内的点。
使用 Point 数据类型将经度和纬度存储在单个列中:
CREATE TABLE table_name (
id integer NOT NULL,
name text NOT NULL,
location point NOT NULL,
created_on timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT table_name_pkey PRIMARY KEY (id)
)
在“位置”列上创建索引:
CREATE INDEX ON table_name USING GIST(location);
GiST 索引能够优化“最近邻”搜索:
SELECT * FROM table_name ORDER BY location <-> point '(-74.013, 40.711)' LIMIT 10;
注意:点的第一个元素是经度,第二个元素是纬度。
有关详细信息,请查看此 Query Operators。
float
数据类型。它使坐标计算变得非常复杂。您应该使用 PostGIS 和geography
数据类型进行此类计算。