MySQL-geometry地理位置数据存储和查询
参考
mysql中geometry类型的简单使用 - 知乎 (zhihu.com)
MySQL Geometry的使用 —— 地理空间类型Geometry - 长歌→ - 博客园 (cnblogs.com)
环境
MySQL 8+
说明
MySQL中支持的几何数据类型包括Geometry(几何)、Point(点)、LineString(线)、Polygon(面)
以及集合类型的MultiPoint(多点)、MultiLineString(多线)、MultiPolygon(多面)、GeometryCollection(混合数据类型)Geometry可以表示其他任意类型的值,剩下的只能表示单个类型的值
WKT(文本格式:在代码中的格式)
WKB(二进制格式:存储在Geometry类型的表字段中)
名称 | 类型 | 文本格式-数据示例 |
---|---|---|
Point | 点坐标 | POINT(103 35) |
LineString | 线坐标 | LINESTRING(103 35,103 36,104 36,105 37) |
Polygon | 面坐标 | POLYGON((103 35,104 35,104 36,103 36,103 35)) |
MultiPoint | 多点 | MULTIPOINT(103 35, 104 34,105 35) |
MultiLineString | 多线 | MULTILINESTRING((103 35, 104 35), (105 36, 105 37)) |
MultiPolygon | 多面 | MULTIPOLYGON(((103 35,104 35,104 36,103 36,103 35)),((103 36,104 36,104 37,103 36))) |
GeometryCollection | 混合类型 | GEOMETRYCOLLECTION(POINT(103 35), LINESTRING(103 35, 103 37)) |
Geometry的常用函数
st_geohash(geometry, length)
计算 geometry 对象的 geohash 值并保留前 length 位
ST_POINTFROMTEXT
坐标点字符串转 point geometry 对象
创建表
- gis 字段 geometry 类型存储空间位置信息,不能为 null
- geohash 字段自动计算 gis 信息的 geohash 并存储,便于后面优化距离等计算的效率
1 | CREATE TABLE `z_gis` ( |
插入数据
- ST_GeometryFromText 方法是将位置字符串转换为 geometry 类型对象
1 | insert into z_gis(id,name,gis) values |
数据查询
查询包含指定坐标点的区域 - ST_Contains
1 | // 设置地理字段-区域信息 |
查询指定范围之内的数据
中心点+半径的圆形区域内 - st_distance_sphere
1 | # 距离点坐标(103,36)2000米之内的数据 |
多边形区域内 - ST_Contains
1 | // 指定多边形内有哪些数据 |
查询张三的位置信息
1 | select name, gis from z_gis where name = '张三'; |
修改张三的位置信息
1 | update z_gis set gis = ST_GeometryFromText('point(108.9465236664 34.2598766768)') where name = '张三'; |
查询张三和李四之间的距离 - st_distance_sphere
st_distance_sphere() 函数计算两点之间距离,需要两个参数,都是 geometry 类型的
floor() 函数是把计算出的距离取整
1 | SELECT |
查询距离张三500米内的所有人
返回数据包含距离
一般查询
- 如果表中数据非常多时,这样查效率会非常低,这时就会用到geohash字段查询
1 | SELECT NAME, FLOOR( |
使用 geohash 字段优化查询
geohash是把经纬度转成字符串,建表的时候我定义让它转成8位字符,当两个点离得越近时,它生成的geohash字符串前面相同的位数越多,所以我在这里先用left()截取前6位字符,前6位相同的误差在±600米左右,然后模糊查询,查出大概符合条件的数据,最后再精确比较
用geohash 查询会有边界问题,所以查询出来的结果又可能不准确,可以用程序(例如java代码)先查出当前点周围8个范围的geohash值,然后再匹配这9个范围的所有数据,这样就解决了geohash 的边界问题
geohash官方文档地址:https://en.wikipedia.org/wiki/Geohash
1 | SELECT NAME, floor( |
geohash
geohash长度 | 误差距离(km) |
---|---|
1 | ±2500 |
2 | ±630 |
3 | ±78 |
4 | ±20 |
5 | ±2.4 |
6 | ±0.61 |
7 | ±0.076 |
8 | ±0.019 |