直接结论:用 point + srid 4326 + spatial index + st_distance_sphere() 是当前 mysql(5.7+)最稳妥、可落地的方案;别再存两个 decimal 字段手动算距离——因平面公式(如 sqrt(pow(lat-?,2)+pow(lon-?,2)))单位是度,非米,且忽略地球曲率,结果无地理意义。

直接结论:用 POINT + SRID 4326 + SPATIAL INDEX + ST_Distance_Sphere() 是当前 MySQL(5.7+)最稳妥、可落地的方案;别再存两个 DECIMAL 字段手动算距离。
为什么不能只用 lat / lon 两个浮点字段?
常见错误现象:WHERE SQRT(POW(lat-?,2) + POW(lon-?,2)) 查询慢、结果不准、加了普通 B-tree 索引也几乎无效。
根本原因有三:
- 地球是球面,欧氏距离在经纬度上误差极大——北京到东京按平面算可能差出 200 公里;
- MySQL 对独立
lat和lon字段无法构建空间索引,WHERE lat BETWEEN ... AND ... AND lon BETWEEN ...仍要扫全表或大量行; - 后续想做“是否在多边形围栏内”“两点间最短路径”等操作时,纯数值字段完全无函数支持,只能应用层硬写,维护成本爆炸。
POINT 字段必须带 SRID 4326 吗?
必须。不指定或错用 SRID 会导致所有空间函数返回 NULL 或错误值,且 MySQL 不报明显错误,极难排查。
关键细节:
-
SRID 4326表示 WGS84 坐标系,即标准经纬度(单位:度),绝大多数地图 SDK(如高德、百度、Leaflet)输出的坐标都属此系; -
POINT的参数顺序是POINT(longitude latitude),不是纬度在前——这是高频翻车点,比如上海是POINT(121.4737 31.2304),不是POINT(31.2304 121.4737); - 建表时就应声明:
coordinates POINT NOT NULL SRID 4326;已有表可:ALTER TABLE locations MODIFY coordinates POINT NOT NULL SRID 4326;; - 插入时必须传 SRID:
ST_GeomFromText('POINT(121.4737 31.2304)', 4326),漏掉第二个参数会默认为 0,导致ST_Distance_Sphere()失效。
如何正确创建空间索引并验证是否生效?
空间索引不是“加了就快”,它只对特定查询模式起作用:范围查询(如矩形框)、邻近查询(ST_Distance_Sphere 配合 HAVING)、包含判断(ST_Contains)。
实操要点:
- 建索引语句必须是:
CREATE SPATIAL INDEX idx_coord ON locations(coordinates);—— 注意是SPATIAL INDEX,不是INDEX或FULLTEXT; - 确认索引存在:
SHOW INDEX FROM locations WHERE Key_name = 'idx_coord';,Type 列应为SPATIAL; - 执行计划中,
EXPLAIN看key列是否显示索引名,且rows显著下降(比如从 10 万降到几百); -
ST_Distance_Sphere()查询本身不会走索引,但配合MBRContains()先粗筛能大幅提速,例如先限定“在中心点 ±0.1 度矩形内”,再精确算球面距离。
ST_Distance_Sphere() 查询为什么有时很慢?
典型低效写法:SELECT *, ST_Distance_Sphere(coordinates, POINT(?,?)) AS d FROM locations HAVING d
问题在于:没做前置过滤,MySQL 仍需计算全表每行的距离。
优化路径:
- 先用
MBRContains()快速排除远距离点(利用空间索引):WHERE MBRContains(ST_Buffer(POINT(?,?), 0.1), coordinates); - 或者更直观地用矩形边界:
WHERE coordinates && ST_MakeEnvelope(?, ?, ?, ?, 4326)(&&是 MBR 重叠操作符); - 再叠加
ST_Distance_Sphere()精确过滤和排序; - 注意:MySQL 8.0.16+ 支持
ST_DWithin()(类似 PostGIS),但 5.7/8.0 早期版本不支持,别盲目套用。
真正容易被忽略的是:空间索引只加速“范围判定”,不加速“逐行距离计算”。把 MBRContains 当作第一道过滤门,才是高效查询的核心逻辑。











