MySQL 支持空间索引。然而,空间索引所能做的就是在一个框中找到点。它不能做一些花哨的事情,比如找到最近的 1000 点等。
我想,而且我不知道我哪里出错了,简单地在框中找到点很容易——只需做约束:
x < xmax and x > xmin and y < ymax and y > ymin
Run Code Online (Sandbox Code Playgroud)
是的,这些是使用至少 2 列的 4 个约束。结果是当有 160 万行时,事情变得太慢了。
但为什么?x 和 y 已排序。复杂度应该是log(n)
。然而,查询可能需要 60 秒。
使用空间索引通过一些子查询技巧将其缩短到 1 秒。
我错过了什么?为什么在查询中使用一堆约束需要时间?
即使没有花哨的算法,也应该很容易快速获得框中的分数。然而,我觉得O(n)
至少应该是复杂的。
这里有多个问题。
回答标题:MySQL 可以为每个查询使用多个索引。这称为索引合并。
但是,使用索引合并优化并不总是发生。
“正常”索引是 B/B+ 树。这种树提供了线性排序。可以索引x
,索引按x
升序排序。您可以对y
. 您甚至可以对两者进行索引,(x, y)
但您仍然可以获得线性排序——而不是二维排序。
回到你的另一个问题,关于查询
x < xmax and x > xmin and y < ymax and y > ymin
Run Code Online (Sandbox Code Playgroud)
让我们假设我们有一个索引 onx
和一个索引 on y
。问题始于这样一个事实,即这些索引不共享资源,也不共享信息,也不以任何方式相互指向。
x < xmax and x > xmin
使用 on 的索引可以很容易地找出所有行 where x
。但是一旦你有了这些,你就不能只是将这些行带到y
索引并要求它“从我给你的这些行中返回行,并为其 y < ymax 和 y > ymin . The reason is that the index on
y can quickly lookup using
y` 值。它不知道如何快速查找行 #3984987。
索引合并的工作方式是从x
索引中获取行 id,从索引中获取行 id y
(同时x
行存储在临时缓冲区中),然后将它们相交。请注意,交集与索引无关。这是一个蛮力操作(希望在线性时间内实现,因为两个行列表已经排序)。
现在给出像你这样的查询,MySQL 会问自己:什么会更便宜?在 上只使用一个索引x
,然后逐行过滤那些y < ymax and y > ymin
适用的行?或者也许使用索引合并,创建一个临时缓冲区,算出一个蛮力交集?
事实是 MySQL 很少选择索引合并优化。我一直在查看许多查询及其执行计划。非常稀有。也许有人经常这样做。
但是看看 X:Y 坐标问题,很容易看出为什么这行不通:仅 x 范围的匹配值太多,而仅 y 范围的匹配值太多,因此无法作为好计划。