2018年1月:高效存储与操作坐标的数据库选型及实现方案
2018年1月:坐标数据高效存储与查询方案选择
在2018年1月这个时间点,针对10万条坐标数据的高效存储与20km圆形范围查询需求,MongoDB和MySQL都有成熟的解决方案,具体选哪个要看你的技术栈和需求细节,下面分别拆解两种方案的实现:
MongoDB 方案(推荐,原生空间支持更省心)
MongoDB的原生2D球面索引在2018年已经非常成熟,处理10万条数据的空间查询完全不在话下,操作也更直观:
- 存储结构:每条文档采用GeoJSON格式存储经纬度(注意MongoDB是先经度后纬度的顺序),示例文档:
{ "_id": ObjectId("..."), "location": { "type": "Point", "coordinates": [116.397228, 39.9075] // 经度,纬度 }, "name": "天安门" // 其他业务字段 } - 创建空间索引:创建
2dsphere索引(针对球面几何的索引,比传统2d索引更适合真实地球的距离计算):db.coordinates.createIndex({ location: "2dsphere" }) - 执行20km范围查询:使用
$geoWithin结合$centerSphere,需要将公里转换为弧度(地球半径约6378.1km,20km对应的弧度是20 / 6378.1),查询语句:
这个查询会直接利用db.coordinates.find({ location: { $geoWithin: { $centerSphere: [ [目标经度, 目标纬度], 20 / 6378.1 ] } } })2dsphere索引,速度非常快,10万条数据的查询基本毫秒级完成。
MySQL 方案(适合已有MySQL技术栈的场景)
2018年时MySQL 5.7+已经原生支持空间数据类型和球面距离计算,不需要自己手动实现kd-tree(原生空间索引的性能已经足够):
- 存储结构:使用
POINT类型存储坐标,创建表结构(推荐用InnoDB引擎,2016年后InnoDB已支持空间索引):
插入数据时可以用CREATE TABLE coordinates ( id INT PRIMARY KEY AUTO_INCREMENT, loc POINT NOT NULL SRID 4326, -- SRID 4326代表WGS84坐标系(GPS常用) name VARCHAR(100), -- 其他业务字段 SPATIAL INDEX idx_loc (loc) );ST_GeomFromText函数:INSERT INTO coordinates (loc, name) VALUES (ST_GeomFromText('POINT(116.397228 39.9075)'), '天安门'); - 执行20km范围查询:用
ST_Distance_Sphere函数直接计算球面距离(单位是米),筛选出20000米内的数据:
如果你的MySQL版本低于5.7,只能用Haversine公式配合普通索引优化,但这种方式需要全表扫描计算距离,性能远不如原生空间索引,不推荐在10万条数据量级使用。SELECT id, name, ST_AsText(loc) AS location FROM coordinates WHERE ST_Distance_Sphere(loc, ST_GeomFromText('POINT(目标经度 目标纬度)')) <= 20000;
方案选择建议
- 如果你的系统已经在用MongoDB,或者需要灵活的文档结构,优先选MongoDB:原生空间支持的API更简洁,索引优化更到位,开发成本更低。
- 如果你的系统是纯MySQL技术栈,不想引入新数据库,且使用MySQL 5.7+版本,选MySQL原生空间方案:性能能满足需求,不需要额外维护MongoDB集群。
内容的提问来源于stack exchange,提问作者phenric
相关产品推荐
相关产品推荐

