使用 POINT 类型存储经纬度比 VARCHAR 更可靠,因其支持空间索引和原生球面距离函数(如 ST_DistanceSphere),需指定 SRID 4326,避免 Haversine 手动计算与索引失效问题。

用 POINT 类型存经纬度比 VARCHAR 更可靠
MySQL 的 POINT 是专门用于地理坐标的几何类型,底层支持空间索引和原生距离函数。如果用 VARCHAR 或两个 DOUBLE 字段存经纬度,后续查“附近 5km 的轨迹点”就得写冗长的 Haversine 公式,还无法走索引。
- 必须在建表时指定 SRID(推荐
4326,即 WGS84 坐标系):CREATE TABLE track_points ( id BIGINT PRIMARY KEY, loc POINT NOT NULL SRID 4326, ts DATETIME, INDEX idx_loc (loc) ) ENGINE=InnoDB;
- 插入时用
ST_PointFromText('POINT(116.48 39.92)', 4326),不能直接写POINT(116.48, 39.92)—— 后者不带 SRID,插入会失败或被静默转为 0 - 查询某点 1km 内的所有记录,用
ST_DistanceSphere()(单位是米):SELECT * FROM track_points WHERE ST_DistanceSphere(loc, ST_PointFromText('POINT(116.48 39.92)', 4326)) <= 1000;
ST_DistanceSphere 和 ST_Distance 的区别必须分清
ST_Distance 在 MySQL 8.0.16+ 默认返回球面距离(单位米),但仅当字段 SRID=4326 且函数参数也带 SRID 时才生效;否则它退化为平面欧氏距离(无意义)。而 ST_DistanceSphere 强制按球面算,更明确、更安全。
- 路径规划类场景(如计算两点间直线距离):用
ST_DistanceSphere(a, b) - 判断是否在圆形区域内(如电子围栏):必须用
ST_DistanceSphere,ST_Within+ST_Buffer效率低且不准(ST_Buffer在地理坐标下生成的是畸形圆) - 注意:MySQL 的
ST_DistanceSphere输入顺序不影响结果,但要求两个点都显式声明 SRID,否则报错SRID mismatch
批量插入轨迹点时避免 ST_PointFromText 性能瓶颈
每条 INSERT 都调用 ST_PointFromText 会显著拖慢吞吐。实测 10 万点插入,用字符串拼接再批量转 POINT 比逐行调用快 3–4 倍。
- 推荐做法:先用应用层拼好 WKT 字符串,用
LOAD DATA INFILE或批量 INSERT:INSERT INTO track_points VALUES (1, ST_GeomFromText('POINT(116.48 39.92)', 4326), '2024-01-01 08:00:00'), (2, ST_GeomFromText('POINT(116.49 39.93)', 4326), '2024-01-01 08:00:05'); - 不要用
ST_PointFromText在 WHERE 或 ORDER BY 中计算——它无法利用索引,会导致全表扫描 - 如果轨迹点密度高(如每秒 10 条),建议按车辆 ID + 时间范围分区,避免单表过大影响
ST_DistanceSphere查询响应
查询“某段轨迹总长度”别直接套用 ST_Length
ST_Length 对 LINESTRING 返回的是平面距离(单位跟 SRID 单位一致,4326 下是“度”),不能直接当公里数用。必须先转成地理线串再用 ST_Length(MySQL 8.0.29+)或手动拆点累加 ST_DistanceSphere。
- 正确方式(MySQL ≥ 8.0.29):
SELECT ST_Length( ST_Transform(ST_GeomFromText('LINESTRING(116.48 39.92, 116.49 39.93)', 4326), 3857) ) AS meters;
注意:这里先转到 Web Mercator(3857)再算长度——但 3857 在高纬度失真严重,仅适合中低纬度粗略估算 - 更稳妥的做法:用应用层读出所有点,两两调用
ST_DistanceSphere累加(适合单次轨迹 ≤ 1000 点) - 容易忽略的一点:轨迹点时间戳是否严格递增?如果存在乱序,
ST_MakeLine生成的线串可能自交或倒退,导致长度计算偏小
空间索引不是银弹。即使加了 INDEX idx_loc (loc),复杂查询如“找出所有经过某区域的车辆轨迹”,仍需配合时间范围过滤,否则优化器大概率放弃空间索引。


















