[英]Mysql, Complex Where clause slows down query
我有一个映射表,其结构如下:
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),它运行得更快,尽管理论上它应该是其他绕着走? 使用覆盖索引时,当我只使用一次使用x和y的简单where子句进行选择查询时:
SELECT id, terrain, c_type, occupied FROM map WHERE x >= $x And y <= $y limit 30;
它的执行速度更快,仅在0.000059中发送数据。 有什么我想念或误解的吗? 也许应该是这样的?
对于仅40K行,建议添加
INDEX(x),
INDEX(y)
这样,优化器可以查看BETWEENs
并选择可能更好的方法,并将工作缩减一些 。
进一步的优化是棘手的。 在标记为[纬度-经度]的问题中重复讨论了它们。
(术语学)“半径”表示2D“距离”。 您拥有的是一个“边界框”。
如果没有ORDER BY
,查询将返回任何30
行,不一定是最接近的30
行。如果您对此满意,可以,因为它更快。
“覆盖索引”与INDEX(x)
-我有一条规则:创建的索引不要超过5列。 这样做并没有什么错,它变得笨重。 我建议也使用INDEX(y)
是基于这样的假设,即y
有时是更好的过滤器。
提防查询缓存-如果将其打开,则可能是由于“更快”运行。 使用SELECT SQL_NO_CACHE ...
运行计时,以获得诚实的比较。
您的6列索引是否唯一? 如果是这样,请使其成为PK,并完全摆脱id
。
如果x
和y
始终为0..200,则将它们设为TINYINT UNSIGNED
(范围为0..255,而不是4个1字节)。
'range'的所有风味(介于BETWEEN
, <=
-2面或1面)均执行相同。 因此,任何性能差异都是其他因素造成的。
LIMIT
且没有ORDER BY
,则停止
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.