【发布时间】:2018-03-21 13:32:39
【问题描述】:
我有一个用于简单反向地理编码的数据库。该数据库依赖于包含纬度、经度和地名的表。每次几个纬度,经度不存在,或者更好的是,每次搜索的纬度,经度与现有的纬度,经度相差太大,我使用谷歌地图反向地理编码服务添加一个新行。 下面是生成地址表的代码:
CREATE TABLE `data_addresses` (
`ID` int(11) NOT NULL COMMENT 'Primary Key',
`LAT` int(11) NOT NULL COMMENT 'Latitude x 10000',
`LNG` int(11) NOT NULL COMMENT 'Longitude x 10000',
`ADDRESS` varchar(128) NOT NULL COMMENT 'Reverse Geocoded Street Address'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `data_addresses`
ADD PRIMARY KEY (`ID`),
ADD UNIQUE KEY `IDX_ADDRESS_UNIQUE_LATLNG` (`LAT`,`LNG`),
ADD KEY `IDX_ADDRESS_LAT` (`LAT`),
ADD KEY `IDX_ADDRESS_LNG` (`LNG`);
ALTER TABLE `data_addresses`
MODIFY `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Primary Key';
如您所见,诀窍是在纬度和经度上放置两个索引。由于通常纬度和经度是浮点数,我们使用它们的值乘以 10000,因此每一对纬度/经度都是唯一的。这意味着大约 50m 的分辨率可以满足我的需求。
现在的问题是:每次我需要知道给定的纬度/经度 (MyLat,MyLon) 是否已经存在时,我都会执行以下查询:
SELECT `id`, ROUND(SQRT(POW(ABS(`LAT`-ROUND(MyLat*10000)),2)+POW(ABS(`LNG`-ROUND(MyLon*10000)),2))) AS R FROM splc_smarttrk.`data_addresses` ORDER BY R ASC LIMIT 1
此查询将返回给我最近的点,并且还会给我 R(评级):较小的 R 意味着最接近的近似值,所以假设每次我找到一个大于 10 的 R 时,我需要添加一个新行地址表。 地址表目前包含大约 615k 行。
问题是尽管我已经放置了索引,但这个查询太慢了(在 2x Xeon 服务器上大约需要 2 秒)。在 Explain 的结果下方:
【问题讨论】:
-
我尝试将解释结果的快照图像上传为图片,但是当您需要上传图像时,stackoverflow 的编辑器很可怕...不要问我为什么在上面页面...
-
您在“计算”列上排序,这从未使用索引进行优化,因为 MySQL 需要对 615088 行的估计使用快速排序排序算法...“使用文件排序”在额外列中关闭解释输出表明..
-
@RaymondNijland,你说得对,这是问题的核心。所以真正的问题是如何检查地址表中可用的纬度/经度中最接近的纬度/经度?我只需要找到最接近的那个,不管我如何检查。是否可以基于纬度和经度对创建“计算索引”?
-
检查我的答案可能会帮助你
-
不要费心让
IDPK两次。
标签: mysql indexing latitude-longitude query-performance