我有一个地图表,其结构如下:
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发送数据。 有什么我遗失或误解?也许它应该是这样的?
答案 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
。
如果x
和y
始终为0..200,则将它们设为TINYINT UNSIGNED
(范围为0..255,而不是4字节)。
所有口味&#39;范围&#39; (BETWEEN
,<=
- 双面或单面)执行相同的操作。因此,任何性能差异都是其他事物的伪影......
LIMIT
到达并且没有ORDER BY