MYSQL 搜索条件的细微差别会产生巨大的差异,我无法理解它
Posted
技术标签:
【中文标题】MYSQL 搜索条件的细微差别会产生巨大的差异,我无法理解它【英文标题】:Slight difference in MYSQL search condition makes huge difference, can't wrap my mind around it 【发布时间】:2018-01-15 10:56:46 【问题描述】:我不能说我是 mysql 方面的专家,更多的是在新手方面。但我知道一些基本的性能成本概念。话虽如此,
我有一个大约 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次!?!?!?!)
由此产生的选择结果差异只有几百(可以理解)。
所以我也尝试更改其他值,看看到底是什么原因造成的。我改变了纬度值。纬度值似乎对性能没有任何影响。卧槽!
我尽量删除索引,并尝试不同的索引变体来解决问题。
仍然没有线索。
所以,我更深入地研究了这一点,我将经度值更改为介于 -105 和 -103.597 之间。 -103.597 需要 49 毫秒,而 -105 和 -103.596 需要 526 毫秒。
0.001 的差异不可能在查询性能上产生这种差异。 我错过了什么???
我正在使用 InnoDB,mysql 版本 5.7.19,顺便说一句。
表架构,
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 正在做什么,两种情况都运行EXPLAIN <query>
。
看来我可能已经找到了我的问题,当它是-103.5时,行数大约是500,000,而当它是-103.6时,它大约是77000。这似乎是造成的问题。并且 Extra 字段也有区别...谢谢。让我深入研究一下。
Afaik 索引的顺序无关紧要。可能发生的是索引统计信息已更新。您应该在gender
上删除索引,它唯一做的就是生成愚蠢的执行计划。只有少数可能值和均匀分布的索引只会产生问题。
【参考方案1】:
MySQL 运行一个内部优化器来确定所有查询的执行计划。
查询中的微小变化(在我的例子中)导致优化器提出完全不同的执行计划,因此其中一个值的微小变化导致结果的巨大差异。
我修复它的方法是更改表的结构(索引等),以便 MySQL 在制定执行计划时有更好的想法。就我而言,修复索引就可以了。我添加了多列索引以在一定程度上迫使优化器走某条路线。
就到这里了,感谢各位网友的帮助。
【讨论】:
以上是关于MYSQL 搜索条件的细微差别会产生巨大的差异,我无法理解它的主要内容,如果未能解决你的问题,请参考以下文章