Mysql,Complex Where子句减慢了查询速度

时间:2017-03-07 20:11:58

标签: php mysql performance latitude-longitude

我有一个地图表,其结构如下:

CREATE TABLE `map` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `occupied` tinyint(2) NOT NULL DEFAULT '0',
  `c_type` tinyint(4) NOT NULL DEFAULT '0',
  `x` int(11) NOT NULL,
  `y` int(11) NOT NULL,
  `terrain` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `get_map_w_radius` (`x`,`y`,`id`,`terrain`,`occupied`,`c_type`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8mb4_general_ci

有40k记录,x和y都是1到200。

在我的脚本中,我使用它:

SELECT id, terrain, occupied, c_type FROM map WHERE x >= $x-$radius AND x <= $x+$radius AND y >= $y-$radius AND y <= $y+$radius LIMIT 30

例如$ x为15,y为95,半径为5。 当我分析查询时,发送数据是0.000496毫秒,但没有覆盖索引(只有x和y代替)它运行得更快,即使理论上它应该是另一种方式? 使用覆盖索引,当我使用简单的where子句使用x和y进行一次select查询时:

SELECT id, terrain, c_type, occupied FROM map WHERE x >= $x And y <= $y limit 30;

执行速度更快,仅在0.000059发送数据。 有什么我遗失或误解?也许它应该是这样的?

1 个答案:

答案 0 :(得分:1)

只需40K行,建议添加

INDEX(x),
INDEX(y)

这样,优化工具可以查看BETWEENs并选择一个可能更好的工作并缩小工作一些

进一步优化是棘手的。在标记为[纬度 - 经度]的问题中反复讨论它们。

(术语狡辩)&#34; Radius&#34;意味着2D&#34;距离&#34;。你所拥有的是一个&#34;边界框&#34;。

如果没有ORDER BY,查询将返回任何30行,不一定是最接近的30行。如果您对此感到满意,那很好,因为它更快。

&#34;覆盖指数&#34; vs INDEX(x) - 我有一个规则:不要创建超过5列的索引。这样做没有什么不妥,它变得笨重。我对INDEX(y)的建议是基于y有时候是更好的过滤器的假设。

谨防查询缓存 - 如果启用了查询缓存,您的速度会更快&#39;运行可能是由于这一点。使用SELECT SQL_NO_CACHE ...运行您的计时,以获得诚实的比较。

你的6-col索引是否具有独特性?如果是这样,那就把它变成PK吧,完全摆脱id

如果xy始终为0..200,则将它们设为TINYINT UNSIGNED(范围为0..255,而不是4字节)。

所有口味&#39;范围&#39; (BETWEEN<= - 双面或单面)执行相同的操作。因此,任何性能差异都是其他事物的伪影......

  1. 将BTree向下钻取到起始值(可能是表格的开头)
  2. 向前扫描
  3. 如果LIMIT到达并且没有ORDER BY
  4. ,请停止
  5. 停在结束值(或表格末尾)