2017-01-09 96 views
2

我有一个'lat'和'lng'字段的表。两者都非常连贯,这意味着他们不会重复太多。这让我相信,为lat和lng制作多列索引对我来说并不会有帮助。我想要做的是这样的:mysql geolat geolng多索引查询

使两个纬度和经度索引,然后执行类似的查询:

select from tableName where 
lat >= 13.1232 and lat <=14.123 and 
lng >=-80.123 and lng <=-79.232 and 
name like '%greg%' 

,并有mysql执行此过程:

  1. 选择14.1232和13.123之间的所有的LAT(这应该被索引,并且快速)

  2. 该步骤#1中找到的组内的,则执行步骤#2:找到LNGS < = -80.123和LNGS> = -79.232(这也应该被编入索引并非常快)

3. 通过步骤中创建#1的组内和#2 ...执行更耗时的关键字搜索。

我该怎么做?我敢肯定,查询的第一部分(索引拉特)正在缩小对我来说...但之后,我不知道...这是我一直在努力寻找在文档

+0

听起来像你已经有了它的工作。你是否在lat&lng列中添加了索引,或者你在问什么? – mba12

+0

即时通讯只是想知道如何处理其查询的顺序...我敢肯定,查询的第一部分(索引纬度)缩小了,但查询的第二部分呢? (索引lng) – rikkitikkitumbo

回答

2

MySQL的处理常规B树索引最喜欢的实现:该指数可以帮助在索引中最左边的列的范围条件。

我使用的比喻是一本电话簿。如果我搜索一个特定的姓氏,像“Smith,John”这样的名字对可以帮助你。我对姓氏“史密斯”的搜索很快,在史密斯内搜索“约翰”很快。

但是如果我搜索了一系列条件,如“所有的人都姓始于‘S’”,然后我得到的电话号簿的一个子集,但不是所有的命名人“约翰”的排序在一起。它们分散在我根据姓氏选择的子集中。

这是因为这个原因,MySQL的检索B树索引到第一个范围条件,再没有任何进一步的使用索引。您仍然可以为其他维度创建条件,但它将对通过第一维匹配的所有行执行手动搜索。

换句话说,即使你有(lat, long)一个复合索引,MySQL不会使用索引的long部分:

select ... from tableName 
where lat >= 14.1232 and lat <=13.123 /* index-assisted */ 
    and lng >=-80.123 and lng <=-79.232 /* full scan */ 
    and name like '%greg%'    /* pattern search never uses index anyway */ 

(顺便说一句,你的LAT条件永远是你真正的已经写了,但我会假设你的意思是要颠倒的数字。)

由于两者都搜索一定范围的值,因此经纬度为&时效率低下。

因此,MySQL有另一种类型的索引,它不是B树索引。这是一个SPATIAL索引,它支持多种范围条件。

CREATE TABLE mytable (
    name TEXT NOT NULL, 
    coord POINT NOT NULL, 
    SPATIAL INDEX (coord) 
); 

INSERT INTO mytable (name, coord) 
VALUES ('name', ST_GeomFromText('POINT(14.0 -80)')); 

SELECT name FROM mytable 
WHERE MBRContains(
    ST_GeomFromText('Polygon((
    13.123 -80.123, 
    14.1232 -80.123, 
    14.1232 -79.232, 
    13.123 -79.232, 
    13.123 -80.123))'), 
    coord); 

是的,这是更复杂的,但它是唯一的方法,你可以得到真正的索引优化的纬度/经度搜索。

阅读更多关于它的地方:http://dev.mysql.com/doc/refman/5.7/en/using-spatial-data.html

+0

这是一个很好的答案......但它也看起来有点凌驾于我的头上,所以在这一点上,我将坚持只把二叉树索引放在经度上。 – rikkitikkitumbo

+1

'INDEX(经度)'不会比'INDEX(纬度)'更好。优化器不会同时使用两者。 –

+0

是的,我同意。我想另一种解决方案是,如果你绝对有必要通过索引真正缩小数据库的范围:制作一些盒子的网格系统,然后在插入时使用特定的盒子名称存储数据...然后在查询数据库时: “给我所有的数据boxField ='x123y123'或任何你的网格系统。boxField可以是可索引的... – rikkitikkitumbo

1

如果你绝对要每个where子句限制结果,以便你可以尝试这样的事情,但一个SQL优化器可能的掩护下,改变的东西设定。我认为一个或两个好的指数仍然是你最好的选择,但我相信这是你所要求的。我建议解释计划来优化您的查询。

select * from 
(
    select * from 
     (
     select * from tableName 
     where lat >= 14.1232 and lat <=13.123 
     ) 
    where lng >=-80.123 and lng <=-79.232 
) 
where name like '%greg%' 
+2

好的......做了更多的研究和测试......并且据我所知...... mysql只使用第一个索引。在这种情况下,您在技术上即时创建新表(并给出别名)......并且您还没有在这些“即时”表上创建索引,因此根据EXPLAIN,唯一使用的索引是“拉特'指数。看起来像这样做的唯一方法是Bill Karwin谈论 – rikkitikkitumbo

+2

@rikkitikkitumbo的“硬”方式,是正确的。这种使用子查询的解决方案没有区别。事实上,它可能会使查询变慢,因为它必须创建临时表。 –