st_distance_sphere返回单位是米而非公里,例如筛选“5公里内门店”时需将条件写为st_distance_sphere(...)

ST_Distance_Sphere 返回单位是米,不是公里
直接调用 ST_Distance_Sphere 得到的是米(meters),这点和很多业务直觉相反——比如想筛选“5公里内门店”,却写成 ST_Distance_Sphere(...) ,结果一条数据都查不到。<br>正确做法是把目标距离换算成米:5公里 → <code>5000,10公里 → 10000。
参数顺序不能颠倒:POINT(longitude, latitude)
MySQL 的 POINT 构造函数严格要求先经度(longitude)、后纬度(latitude),和常见地图 API(如高德、Leaflet)一致,但和部分 GIS 文档或 Python 库(如 Shapely 默认 lat/lon)相反。传反会导致距离严重失真,甚至跨洲计算。
常见错误写法:POINT(lat, lng) → 实际算的是赤道附近一个错位几千公里的点。
正确写法示例:
SELECT ST_Distance_Sphere( POINT(116.4805, 39.9896), -- 北京某地:lng, lat POINT(121.4737, 31.2304) -- 上海某地:lng, lat );
字段类型必须是 POINT,且 SRID=4326
ST_Distance_Sphere 要求两个参数都是带地理坐标系标识(SRID)的 POINT 值,且隐式要求 SRID = 4326(WGS84)。如果字段定义为 POINT 但没显式指定 SRID,或用字符串/浮点数临时拼 POINT(),MySQL 可能不报错但返回 0 或 NULL。
检查方式:SELECT ST_SRID(your_point_column) FROM your_table LIMIT 1; —— 非 4326 就得转换。
建表或修复建议:
- 建表时明确声明:
location POINT SRID 4326 - 插入时用
ST_GeomFromText('POINT(116.4805 39.9896)', 4326),别用裸POINT() - 已有数据无 SRID?可用
ST_SRID(your_col, 4326)临时包装(仅查询,不持久)
性能差?加空间索引也没用
ST_Distance_Sphere 是计算密集型操作,即使对 POINT 字段加了 SPATIAL 索引,MySQL 也无法在该函数上做索引下推——它只能加速范围预过滤(比如先用 ST_Within 框出大致区域),不能跳过逐行球面距离计算。
真实场景优化建议:
- 先用经纬度边界粗筛:
WHERE lng BETWEEN ? AND ? AND lat BETWEEN ? AND ?(配合普通 B-tree 索引) - 再在结果集里用
ST_Distance_Sphere精排或过滤 - 避免在大表上无条件 SELECT + ORDER BY distance —— 它会强制全表计算
复杂点在于:球面距离没有线性边界,简单矩形框会漏掉斜角近点(比如正西偏北一点的位置),所以边界要适当放宽,再靠函数兜底。











