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 在制定执行计划时会有更好的想法。就我而言,修复索引就成功了。我添加了多列索引以某种程度上强制优化器走特定路线。
我就到这里了,感谢所有评论者的帮助。
我不能说我是 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 在制定执行计划时会有更好的想法。就我而言,修复索引就成功了。我添加了多列索引以某种程度上强制优化器走特定路线。
我就到这里了,感谢所有评论者的帮助。