未使用空间索引

Spatial Index not being used

我在 GEO_LOCATION 列上有一个空间索引,但是当我执行 EXPLAIN 时,它没有显示正在使用该索引。谁能告诉我为什么?

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

id: 1
select 类型:简单
table:人
类型:全部
possible_keys: 空
键:NULL
key_len: 空
参考:NULL
行数:612602
额外:使用 where

这是我的环境:
服务器类型: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

很遗憾 ST_Distance() < threshold isn't a sargable 搜索条件。为满足此查询,MySQL 必须计算 table 中每一行的函数值,然后将其与阈值进行比较。所以它必须进行完整的 table 扫描(或者可能是完整的索引扫描)。

要利用索引来加速此查询,您将需要一个边界框标准。查询更详细,但也更快。假设您的几何图形中的 x/y 点以度数表示 latitude/longitude,则该查询可能如下所示:

   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) function is sargable。另一方面,大而丑陋的 concat 项目会产生一条从边界矩形的西南角到东北角的对角线。使用您的数据点和十英里半径,它看起来像这样。

LINESTRING(37.8785 -94.2564,38.1684 -93.8884)

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

第三,ST_Distance(),在MySQL中,不处理大圆经纬度计算。 (PostgreSQL has a more comprehensive GIS extension.) MySQL 就像平原上的烙饼一样笨。它假定您的几何对象中的点以平面几何表示。所以 ST_Distance() < 10.0 和 lng/lat 点做了一些奇怪的事情。

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

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