惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Blog — PlanetScale
Blog — PlanetScale
B
Blog
A
About on SuperTechFans
大猫的无限游戏
大猫的无限游戏
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Help Net Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 三生石上(FineUI控件)
有赞技术团队
有赞技术团队
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
IT之家
IT之家
D
Docker
Google DeepMind News
Google DeepMind News
罗磊的独立博客
T
The Blog of Author Tim Ferriss
aimingoo的专栏
aimingoo的专栏
博客园 - 叶小钗
Recent Announcements
Recent Announcements
阮一峰的网络日志
阮一峰的网络日志
D
DataBreaches.Net
博客园 - 司徒正美
Engineering at Meta
Engineering at Meta

祈雨的笔记

安全多方计算MPC spark原理解析 kueue执行源码分析 spark on k8s执行源码分析 spark-operator源码解析 系统压测遇到的缓存击穿问题 我的世界PC与安卓联机 蚂蚁金服流量投放平台的AIG改造 G1大对象致Old区占用率高 日志打印导致接口响应率下跌分析 Groovy加载类导致OOM分析 ERROR日志打印导致CPU满载 记OceanBase死锁超时 应用发版期间服务响应超时 Ark Serverless初探 系统优化复盘一二三 The user specified as a definer does not exist Kong网关初探 API网关选型调研 CPU火焰图常用工具 配置中心选型调研 root操作Nginx导致用户组错误 基于Proxifier使用代理 FastJSON字段智能匹配踩坑 Nacos初探 记一次Nginx服务器CPU满荷载故障 基于券系统分库分表的思考 limit不参与SQL成本计算致索引失效 Linux常用性能监控命令 golang低版本http2偶现400
mysql空间索引
祈雨的笔记 · 2019-12-01 · via 祈雨的笔记

空间索引示例

1
2
3
4
5
6
7
CREATE TABLE `shop_info` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`shop_name` varchar(64) NOT NULL COMMENT '门店名称',
`geom_point` geometry NOT NULL COMMENT '经纬度',
PRIMARY KEY (`id`),
SPATIAL KEY `geom_index` (`geom_point`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

初始化500万条测试数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
delimiter  //
CREATE PROCEDURE init_shop_info()
BEGIN
DECLARE count INT;
DECLARE batch INT;
DECLARE initLong INT;
DECLARE initLat INT;
SET count = 0;
SET initLong = 121;
SET initLat = 31;
WHILE count < 5000000 DO
SET batch = 0;
START TRANSACTION;
WHILE batch < 1000 DO
insert into shop_info(shop_name, geom_point) values (concat('shop', count), Point(initLong + Rand(),initLat + Rand()));
SET batch = batch + 1;
SET count = count + 1;
END WHILE;
COMMIT;
END WHILE;
END //
delimiter ;
call init_shop_info();

经纬度距离计算

image

如果知道两个点的纬度和经度,则可以计算它们之间的距离。计算该距离的最简单方法是假设地球是一个完美的球体。但实际上地球是一个两极稍扁、赤道略鼓的不规则球体,因此许多情况下仅仅是计算一个合理的近似值。

1
2
3
4
5
6
7
8
9
10
11
12
1个纬度 ≈ 69英里(111km),与经度无关

在纬度 = 0的赤道处,1度经度 ≈ 69英里(111km),但这随纬度而变化:
纬度±10,1度经度 = 68英里(109km)
纬度±20,1度经度 = 65英里(104km)
纬度±30,1度经度 = 60英里(96km)
纬度±40,1度经度 = 53英里(85km)
纬度±50,1度经度 = 44英里(71km)
纬度±60,1度经度 = 35英里(56km)
纬度±70,1度经度 = 24英里(38km)
纬度±80,1度经度 = 12英里(19km)
纬度±90,1度经度 = 0英里(0km)

SQL

执行SQL获取附近2KM以内的记录。

粗精度

为了指定位置周围创建边界矩形(以便可以利用其上的空间索引),可以使用经度和纬度之间的平均距离111公里。每纬度近似111km,而每经度则超过111km。因此创建出来的边界矩形会比实际需求的边界大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14

set @longitude = 121.5;

set @latitude = 31.5;

set @distance = 2000;

select id, x(geom_point) longitude, y(geom_point) latitude, ST_Distance_Sphere(Point(@longitude, @latitude), geom_point) as distance
from shop_info
where MBRContains(ST_MakeEnvelope(
point((@longitude+(@distance/1000/111)), (@latitude+(@distance/1000/111))),
point((@longitude-(@distance/1000/111)), (@latitude-(@distance/1000/111))))
, geom_point)
order by distance limit 10;

细精度

如果需要边界矩形更精确,则可以使用cos(radians(${latitude})) * 111进行经度计算。示例SQL如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

set @longitude = 121.5;

set @latitude = 31.5;

set @distance = 2000;

select id, x(geom_point) longitude, y(geom_point) latitude, ST_Distance_Sphere(Point(@longitude, @latitude), geom_point) as distance
from shop_info
where MBRContains(ST_MakeEnvelope(
point((@longitude+(@distance/1000/111*cos(radians(@latitude)))), (@latitude+(@distance/1000/111))),
point((@longitude-(@distance/1000/111*cos(radians(@latitude)))), (@latitude-(@distance/1000/111))))
, geom_point)
order by distance limit 10;

注:ST_MakeEnvelopeST_Distance_Sphere从MYSQL 5.7.6版本开始支持,ST_Distance_Sphere返回的单位为米。