MySQL 经纬度范围查询性能优化
知识点:经纬度 1 度等于多少公里?
地球赤道上环绕地球一周走一圈共40075.04公里,而@一圈分成360°,而每1°(度)有60,每一度一秒在赤道上的长度计算如下:
40075.04km/360°=111.31955km
111.31955km/60=1.8553258km=1855.3m
任意两点距离计算公式为
d=111.12cos{1/[sinΦAsinΦB十cosΦAcosΦBcos(λB—λA)]}
其中A点经度,纬度分别为λA和ΦA,B点的经度、纬度分别为λB和ΦB,d为距离。
所以可知每度大概为111千米
指定中心坐标点,查询 5 公里范围内的兴趣点
中心点经度:114.091795,纬度:30.3393,范围:5km
表x_third_data,数据量 3600000 条
maplng为数据表经度字段
maplat为数据表纬度字段
查询结果集数据量 23500 条
优化前 SQL(耗时 9.30 s)
# 设定中心点坐标
set @lng = 114.293488,@lat = 30.589297;
# 查询 5 公里范围内的 POI 数据(优化前)
SELECT
`id`,`name`,`maplng`,`maplat`
FROM
`x_third_data`
WHERE
sqrt(
(
(
( @lng - `maplng` ) * PI( ) * 12656 * cos(
( ( @lat + `maplat` ) / 2 ) * PI( ) / 180
) / 180
) * (
( @lng - `maplng` ) * PI( ) * 12656 * cos (
( ( @lat + `maplat` ) / 2 ) * PI( ) / 180
) / 180
)
) + (
(
( @lat - `maplat` ) * PI( ) * 12656 / 180
) * (
( @lat - `maplat` ) * PI( ) * 12656 / 180
)
)
) < 5;
优化后 SQL(耗时 0.65 s)
# 设定中心点坐标
set @lng = 114.293488,@lat = 30.589297;
# 查询 5 公里范围内的 POI 数据(优化后)
SELECT
`id`,`name`,`maplng`,`maplat`
FROM
`x_third_data`
WHERE
`maplat` BETWEEN (@lat - 0.1) AND (@lat + 0.1)
AND `maplng` BETWEEN (@lng - 0.1) AND (@lng + 0.1)
AND sqrt(
(
(
( @lng - `maplng` ) * PI( ) * 12656 * cos(
( ( @lat + `maplat` ) / 2 ) * PI( ) / 180
) / 180
) * (
( @lng - `maplng` ) * PI( ) * 12656 * cos (
( ( @lat + `maplat` ) / 2 ) * PI( ) / 180
) / 180
)
) + (
(
( @lat - `maplat` ) * PI( ) * 12656 / 180
) * (
( @lat - `maplat` ) * PI( ) * 12656 / 180
)
)
) < 5;
查询 5 公里范围内兴趣点并按距离中心点的距离排序
# 设定中心点坐标
set @lng = 114.293488,@lat = 30.589297;
# 查询 5 公里范围内的 POI 数据按距离排序
SELECT
`id`,`name`,`maplng`,`maplat`,
(st_distance (point (maplng, maplat), point(@lng, @lat)) * 111195) AS distance
FROM
`x_third_data`
WHERE
`maplat` BETWEEN (@lat - 0.1) AND (@lat + 0.1)
AND `maplng` BETWEEN (@lng - 0.1) AND (@lng + 0.1)
HAVING distance < 1000
ORDER BY distance ASC