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

Posted

技术标签:

【中文标题】Mysql,复杂的Where子句减慢查询速度【英文标题】:Mysql, Complex Where clause slows down query 【发布时间】:2017-03-07 20:11:57 【问题描述】:

我有一个结构如下的地图:

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,radius 是 5。 当我分析查询时,发送数据是 0.000496 毫秒,但没有覆盖索引(只有 x 和 y 代替)它运行得更快,即使理论上它应该是其他方式? 使用覆盖索引,当我使用简单的 where 子句进行选择查询时,只使用 x 和 y 一次:

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

它的执行速度要快得多,仅以 0.000059 发送数据。 我有什么遗漏或误解吗?应该是这样吧?

【问题讨论】:

4 个比较 > 2 个比较? 是的,但这看起来太多了。那么,也许有什么需要改进的地方? 等一下,如果您使用包含 2 列的索引而不是包含 6 列的索引,为什么查询会运行得更快? get_map_w_radius 键已经有 x 和 y 了,对吧? mysql 可能没有使用索引,因为您没有过滤其他 4 列 【参考方案1】:

如果只有 40K 行,建议添加

INDEX(x),
INDEX(y)

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

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

(术语狡辩)“半径”意味着二维“距离”。你所拥有的是一个“边界框”。

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

“覆盖索引”与INDEX(x)——我有一条规则:不要创建超过 5 列的索引。这样做并没有什么错,它会变得笨重。我也有INDEX(y) 的建议是基于y 有时是更好的过滤器的假设。

注意查询缓存——如果它被打开,你的“更快”运行可能是由于这个原因。使用SELECT SQL_NO_CACHE ... 运行您的时间,以获得诚实的比较。

您的 6 列索引是唯一的吗?如果是,那就PK吧,彻底摆脱id

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

“范围”的所有风格(BETWEEN&lt;= - 2 面或 1 面)执行相同。所以任何性能差异都是其他事物的产物......

    向下钻取 BTree 到起始值(可能是表的开头) 向前扫描 如果LIMIT 到达则停止并且没有ORDER BY 在结束值(或表的结尾)处停止

【讨论】:

以上是关于Mysql,复杂的Where子句减慢查询速度的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:在 WHERE 子句中带有 NOT IN 的从属子查询非常慢

ORDER BY 子句是不是会减慢查询速度?

为啥 MYSQL 更高的 LIMIT 偏移量会减慢查询速度?

7_mysql查询之where子句

Mysql 查询速度慢怎么办

包括临时表中的值会减慢查询速度