没有使用空间索引

时间:2016-01-29 20:37:17

标签: mysql indexing mariadb spatial

我在GEO_LOCATION列上有空间索引,但是当我执行EXPLAIN时,它并没有显示正在使用索引。有谁能说出原因?

EXPLAIN 
SELECT AsText(GEO_LOCATION) 
FROM PERSON 
WHERE ST_Distance(POINT(-94.0724223,38.0234332), GEO_LOCATION) <= 10

id:1
选择类型:SIMPLE
表:人员 类型:所有
possible_keys:NULL
key:NULL
key_len:NULL
ref:NULL
行:612602
额外:使用

这是我的环境:
服务器类型:MariaDB
服务器版本:10.1.8-MariaDB - mariadb.org二进制分发
协议版本:10
服务器字符集:UTF-8 Unicode(utf8)
Apache / 2.4.17(Win32)OpenSSL / 1.0.2d PHP / 5.6.14
数据库客户端版本:libmysql - mysqlnd 5.0.11-dev - 20120503
PHP扩展:mysqli文档
PHP版本:5.6.14

1 个答案:

答案 0 :(得分:2)

不幸的是ST_Distance() < threshold不是sargable搜索条件。为了满足此查询,MySQL必须为表中的每一行计算函数值,然后将其与阈值进行比较。因此,它必须进行全表扫描(或者可能是完整的索引扫描)。

要利用索引来加速此查询,您需要一个边界框标准。查询更精细,但速度也快得多。假设几何体中的x / y点表示以度为单位的纬度/经度,则该查询可能如下所示:

   set @latpoint = 38.0234332;
   set @lngpoint = -94.0724223;
   set @r = 10.0;    /* ten mile radius */
   set @units=69.0;    /* 69 statute miles per degree */
   SELECT AsText(geo) 
     FROM markers
      WHERE MbrContains(GeomFromText( 
       CONCAT('LINESTRING(', @latpoint-(@r/@units),' ',
                             @lngpoint-(@r /(@units* COS(RADIANS(@latpoint)))), 
                          ',', 
                             @latpoint+(@r/@units) ,' ', 
                             @lngpoint+(@r /(@units * COS(RADIANS(@latpoint)))),
                           ')')),
                    geo) 

这是如何工作的?首先,MbrContains(bound,item)函数 sargable。另一方面,丑陋的大丑项目产生了从边界矩形的西南角到东北角的对角线。使用您的数据点和十英里半径,它看起来像这样。

LINESTRING(37.8785 -94.2564,38.1684 -93.8884)

当您在GeomFromText()的第一个参数中使用该对角线的MbrContains()渲染时,它将用作边界矩形。然后MbrContains()可以利用漂亮的四叉树几何索引。

第三,MySQL中的ST_Distance()并不能处理大圆纬度和经度计算。 (PostgreSQL有一个更全面的GIS extension。)MySQL就像平地里的烙饼一样愚蠢。它假设您的几何对象中的点以平面几何体表示。所以带有lng / lat点的ST_Distance() < 10.0会有些奇怪。

此查询生成的结果存在一个缺陷;它返回边界框中的所有点,而不仅仅是在指定的半径范围内。这可以通过单独的距离计算来解决。我已经写了所有这些in some detail here

注意:对于GPS分辨率的纬度和经度,32位FLOAT数据具有足够的精度。 DOUBLE是MySQL的地理扩展使用的。当你以度数工作时,小数点后超过五个位置超出了GPS的精度。 DECIMAL()不是lat / lng坐标的理想数据类型。