【问题标题】:Why is this query slow over certain ranges of data and fast over others?为什么此查询在某些数据范围内速度较慢,而在其他数据范围内速度较快?
【发布时间】:2014-11-03 07:33:16
【问题描述】:

我在 MySQL 表中有大约 100 亿行坐标为 (x double, y double, z double) 的点。我在 xyz 列上创建了索引索引,因此按范围过滤既好又快。

查询模板:{} 中的内容被替换为实际值)

select id from points_table where
    x between {x-5} and {x+5} and
    y between {y-5} and {y+5} and
    z between {z-5} and {z+5};

现在,奇怪的是,这个查询始终在某些点上花费了大约 0.05 秒,而在其他点上花费了大约 1.5 秒,即使返回的结果数量大致相同。

其中一个例子是,

对于(x,y,z) = (1,5,-6),查询需要大约 0.04 秒并获取 45 个结果,但是,

对于 (x,y,z) = (-2,0,3) 查询需要约 1.20 秒并获取 38 个结果

这对我来说似乎很奇怪。这种行为的原因可能是什么?

编辑:按照这里的要求对这两个查询进行解释,

explain select id from points_table where x between 1-5 and 1+5 and y between 5-5 and 5+5 and z between -6-5 and -6+5; 
+----+-------------+--------------+-------+-------------------+-------+---------+------+-------+-----------------------------------------------+
| id | select_type | tab          | type  | possible_keys     | key   | key_len | ref  | rows  | Extra                                         |
+----+-------------+--------------+-------+-------------------+-------+---------+------+-------+-----------------------------------------------+
|  1 | SIMPLE      | points_table | range | pnt_x,pnt_y,pnt_z | pnt_y | 9       | NULL | 18748 | Using index condition; Using where; Using MRR |
+----+-------------+--------------+-------+-------------------+-------+---------+------+-------+-----------------------------------------------+


explain select id from points_table where x between -2-5 and -2+5 and y between 0-5 and 0+5 and z between 3-5 and 3+5; 
+----+-------------+--------------+-------+-------------------+-------+---------+------+--------+-----------------------------------------------+
| id | select_type | tab          | type  | possible_keys     | key   | key_len | ref  | rows   | Extra                                         |
+----+-------------+--------------+-------+-------------------+-------+---------+------+--------+-----------------------------------------------+
|  1 | SIMPLE      | points_table | range | pnt_x,pnt_y,pnt_z | pnt_y | 9       | NULL | 235748 | Using index condition; Using where; Using MRR |
+----+-------------+--------------+-------+-------------------+-------+---------+------+--------+-----------------------------------------------+

我认为只使用了y 的索引,行数也有很大差异,这可以解释时间差距。

但现在我的问题是,

如何让 mysql 使用所有索引?他们在那里是有原因的。

编辑:

所以我创建了一个复合键 (x, y, z),MySQL 在执行范围过滤时似乎更喜欢它,而且查询花费的时间也始终更少。

【问题讨论】:

  • 请出示执行计划。 MySQL 可能不使用多个索引,并且数据倾斜可能是不幸的。您能否分别发布三个维度中的计数(where x between 1-5 and 1+5 等)。
  • 除了执行计划和统计信息 - 表架构
  • 18748 vs 235748 --- 这是一个数量级的扫描差异。
  • 您可以尝试使用复合索引。但是字段的顺序很重要,把最严格的字段放在第一位(如果在这方面有任何明显的区别)。
  • @zerkms 我创建了一个复合键 (x, y, z),MySQL 在执行范围过滤时似乎更喜欢它,而且查询花费的时间也始终更少,来自EXPLAINExtra 读取@987654336 @我猜这是好事

标签: mysql sql database performance optimization


【解决方案1】:

查询计划会告诉您真正使用的是哪个索引 - 但出于讨论目的,我们假设始终使用 Y。

您可能会看到类似于索引 X 选择 18,748 行并且 X 和 Z 范围过滤掉除 45 行之外的所有行的情况,但是对于第二个查询,索引 X 选择 235,748 行并且 X 和 Z 范围将结果过滤到38 行。

相同的查询,相同的执行计划,不计算 I/O 量,但在第二个查询中处理更多数据以获得总行数相似的结果。

使用 zerkms 建议的实际查询计划信息更新了此答案。

【讨论】:

  • 如果您不在页面上,只需 ping:OP 已更新问题,因此可以使用实际数字更新答案 :-)
猜你喜欢
  • 2013-07-16
  • 1970-01-01
  • 2023-03-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-09
相关资源
最近更新 更多