具有复杂索引的 MySQL 查询优化

标签 mysql indexing latitude-longitude query-performance

我有一个用于简单反向地理编码的数据库。数据库依赖于包含纬度、经度和地名的表。每当有几个纬度、经度不存在,或者更好的是,每次搜索到的纬度、经度与现有的纬度、经度相差太多时,我都会使用 GoogleMaps 反向地理编码服务添加一个新行。 下面是生成地址表的代码:

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';

如您所见,诀窍是在 Latitude 和 Longitude 上使用 place 两个索引。由于纬度和经度通常是 float ,我们将它们的值乘以 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 秒)。下面解释的结果:

enter image description here

最佳答案

您不能通过检索附近纬度和经度的固定数据集并计算评级 (R) 并在此固定数据集上选择最小评级来优化它。

p.s 未测试可能包含排序错误。但它可能会对您有所帮助。

SELECT 
   id 
 , ROUND(SQRT(POW(ABS(`LAT`-ROUND([LAT]*10000)),2)+POW(ABS(`LNG`- ROUND([LNG]*10000)),2))) AS R

FROM ( 

  SELECT 
   LAT 
  FROM  
   data_addresses
  WHERE 
   LAT <= [LAT]  
  ORDER BY
   LAT DESC
  LIMIT 100

  UNION ALL

  SELECT 
   LAT   
  FROM 
   data_addresses
  WHERE 
   LAT >= [LAT]
  ORDER BY
   LAT ASC
  LIMIT 100

  SELECT 
   LNG 
  FROM 
   data_addresses
  WHERE 
   LNG <= [LNG]
  ORDER BY
   LNG DESC
  LIMIT 100

  UNION ALL

  SELECT 
   LNG
  FROM 
   data_addresses
  WHERE 
   LNG >= [LNG]
  ORDER BY
   LNG ASC
  LIMIT 100
) 
 AS data_addresses_range
ORDER BY 
 R ASC
LIMIT 1

关于具有复杂索引的 MySQL 查询优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49407746/

相关文章:

mysql - 使用多行的更新条件加入 MySQL

mysql - 根据枚举值和按日期分组获取多列中的最高分数和名称

wordpress - 在wordpress中使用index.php而不是single.php加载单页

python - Pandas 数据帧 : complete spec for __getitem__()?

Android google-maps 经度/纬度计算问题

php - Mysql,复杂的Where子句会减慢查询速度

php - CKEditor 上传代码片段 - SQL 错误

mysql - 错误: load data not allowed in stored procedures

arrays - MongoDB 和数组上的覆盖索引可能吗?

unity-game-engine - Unity 中球体位置的经度和纬度