繁体   English   中英

Mysql,复杂Where子句减慢查询速度

[英]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

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

'range'的所有风味(介于BETWEEN<= -2面或1面)均执行相同。 因此,任何性能差异都是其他因素造成的。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM