MYSQL 搜索条件的微小差异会造成巨大差异,我无法理解它

Slight difference in MYSQL search condition makes huge difference, can't wrap my mind around it

我不能说我是 MySQL 方面的专家,更像是新手。但我知道一些基本的性能成本概念。话虽如此,

我有一个 table 大约 100 万行的用户配置文件。我想过滤值并只取回我感兴趣的内容。

在列中,我有纬度和经度列。

为了过滤它的“距离”方面,我创建了一个具有纬度范围经度范围的任意矩形。

除了“距离”属性,我还有一些通用属性用于过滤:如年龄、性别等。

我索引了所有字段,包括纬度和经度。我使用 FLOAT 类型表示纬度和经度,顺便说一句。

所以,这是一个简单的 SELECT 查询,具有多个属性,就像这样,

SELECT user_id FROM profiles WHERE gender = 1 AND birthday BETWEEN '1980-01-27' AND '1988-01-27' AND longitude BETWEEN -105 AND -103.6 AND latitude BETWEEN 35 AND 40

************ 这是最奇怪的事情 **************

当我使用介于 -105 和 -103.6 之间的经度过滤器值(以及其他属性)进行测试时,查询运行相对较快 (49 毫秒)。但是当我将经度值更改为 -105 和 -103.5 之间(0.1 差异!)时,查询需要 493 毫秒。 (10 次!?!?!?!)

由此产生的select结果差异只有几百(可以理解)。


所以我也尝试更改其他值,看看到底是什么导致了这种情况。我改变周围的纬度值。纬度值似乎对性能没有任何影响。卧槽!

我什至删除了索引,并尝试了不同的索引变体以解决问题。

仍然没有线索。

因此,我对此进行了更深入的研究,将经度值更改为介于 -105 和 -103.597 之间。 -103.597 需要 49 毫秒,而 -105 和 -103.596 需要 526 毫秒。

0.001 的差异不可能在查询性能上产生这种差异。 我错过了什么???

我正在使用 InnoDB,mysql 版本 5.7.19,顺便说一句。

table 架构,

CREATE TABLE `profiles` (
  `user_id` varchar(8) NOT NULL DEFAULT '',
  `gender` tinyint(1) NOT NULL DEFAULT '0',
  `orientation` tinyint(1) NOT NULL DEFAULT '0',
  `birthday` date NOT NULL DEFAULT '2000-01-01',
  `height` tinyint(2) NOT NULL DEFAULT '0',
  `ethnicity` int(2) NOT NULL DEFAULT '0',
  `latitude` float NOT NULL DEFAULT '0',
  `longitude` float NOT NULL DEFAULT '0',
  PRIMARY KEY (`user_id`),
  KEY `gender` (`gender`),
  KEY `birthday` (`birthday`),
  KEY `longitude` (`longitude`),
  KEY `latitude` (`latitude`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


MySQL 运行内部优化器以确定所有查询的执行计划。

查询中的微小变化(在我的例子中)导致优化器提出了一个完全不同的执行计划,因此其中一个值的微小变化导致结果的巨大差异。

我修复它的方法是更改​​ table(索引等)的结构,以便 MySQL 在制定执行计划时会有更好的想法。就我而言,修复索引就成功了。我添加了多列索引以某种程度上强制优化器走特定路线。

我就到这里了,感谢所有评论者的帮助。