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

标签 php mysql performance latitude-longitude

我有一个结构如下的 map 表:

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 id, terrain, c_type, occupied FROM map WHERE x >= $x And y <= $y limit 30;

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

最佳答案

对于仅有 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<= - 2 面或 1 面)执行相同。因此,任何性能差异都是其他因素造成的......

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

关于php - Mysql,复杂的Where子句会减慢查询速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42657422/

相关文章:

php - 我们可以通过多少种方式通过页面之间的导航传递变量?

mysql - 解释为什么mysql查询结果看起来像分组数据

性能问题: Generating many blob shared access signatures is very slow

PHP 在连字符数组中查找缺失的数字

php - 如何获取 PHP 脚本的运行时间

Mysql:添加外键不会在 MyISAM 表上给出警告/错误

python - 生成包含随机 boolean 值的大型 numpy 数组的内存有效方法

php - 将数据从文件写入数据库并更新旧数据

php - 使用映射数组与具有部分键的数组合并关联数组(支持命名参数)

php - 将 MySQL 查询字段作为数组处理是否有意义?