Mysql 主索引与索引的查询性能
我有一个关于mysql的表和两个性能完全不同的查询。我已经提取了查询计划,但我无法完全理解性能差异背后的原因 下表:Mysql 主索引与索引的查询性能,mysql,performance,innodb,Mysql,Performance,Innodb,我有一个关于mysql的表和两个性能完全不同的查询。我已经提取了查询计划,但我无法完全理解性能差异背后的原因 下表: +-------------+----------------------------------------------+------------------------------------+ | TableA | |
+-------------+----------------------------------------------+------------------------------------+
| TableA | | |
+-------------+----------------------------------------------+------------------------------------+
| id | int(10) unsigned NOT NULL AUTO_INCREMENT | |
| userId | int(10) | unsigned DEFAULT NULL |
| created | timestamp | NOT NULL DEFAULT CURRENT_TIMESTAMP |
| PRIMARY KEY | id | |
| KEY userId | userId | |
| KEY created | created | |
+-------------+----------------------------------------------+------------------------------------+
键/索引:id
字段上的主键,以及userId
字段ASC上的键
,在创建的字段ASC上的另一个键
table a
是一个非常大的表,它包含数百万行
我在此表上运行的查询是:
id为1234
的用户在此表中有150万条记录。我想取最近的100行。为了实现这一点,我有两个不同的查询:
问题1:
SELECT * FROM tableA USE INDEX (userId)
WHERE userId=1234 ORDER BY created DESC LIMIT 100;
问题2:
SELECT * FROM tableA
WHERE userId=1234 ORDER BY id DESC LIMIT 100;
由于tableA
的id
字段是自动递增的,因此保留最新的条件。这两个查询返回相同的结果。但是,存在巨大的性能差异
查询计划包括:
+----------+-----------------------------------------------+-------------------------------+------+---------------------------------------+
| Query No | Operation | Params | Raws | Raw desc |
+----------+-----------------------------------------------+-------------------------------+------+---------------------------------------+
| Query 1 | Sort(using file sort) Unique index scan (ref) | table: tableA; index: userId; | 2.5M | Using index condition; Using filesort |
| Query 2 | Unique index scan (ref) | table: tableA; index: userId; | 2.5M | Using where |
+----------+-----------------------------------------------+-------------------------------+------+---------------------------------------+
+--------+-------------+
| | Performance |
+--------+-------------+
| Query1 | 7,5 s |
+--------+-------------+
| Query2 | 741 ms |
+--------+-------------+
我知道查询1上有一个排序操作。在每个查询中,使用的索引是userId
。但是为什么在查询2中不使用排序呢?主索引是如何影响的
Mysql 5.7
编辑:表上有更多的列,我已经从上面的表定义中提取了它们
由于tableA的id字段是自动递增的,所以保留最新的条件
这通常是一个有效的说法
WHERE userId=1234 ORDER BY created DESC LIMIT 100
需要此“复合”索引:(userId,已创建)
。这样,不管该用户的表大小或行数是多少,它只会命中100行
同样的道理也适用于
WHERE userId=1234 ORDER BY id DESC LIMIT 100;
也就是说,它需要(userId,id)
。然而,在InnoDB中,当你说INDEX(x)
时,它会悄悄地加在主键
列上。因此,您可以有效地获得索引(x,id)
。这就是为什么普通的索引(userId)
工作得很好
EXPLAIN
很少(如果有)考虑限制
。这就是为什么两个查询的“行”都是“250万”
如果您取出USE INDEX
提示,第一个查询可能(也可能没有)使用了INDEX(userId)
。选择取决于表中用户ID=1234的百分比。如果低于20%,则使用该指数。但它将在二级指数和数据之间来回反弹——都是150万次。如果超过20%,只需读取所有“数百万”行,忽略那些不适用的行,就可以避免反弹
注意:对于Q1,您仍然会读取至少150万行,对它们进行排序(“使用文件排序”),然后剥离所需的100行。但是使用索引(userId,created)
,它可以跳过排序,只查看100行
我无法解释“唯一索引扫描”,除非看到SHOW CREATE TABLE
和未注释的explain
。(EXPLAIN FORMAT=JSON SELECT…
可能会提供更多信息。)您忘记告诉我们您已经在此表上创建了哪些索引。这两个查询的相对性能如何?@TimBiegeleisen我已经在表上添加了性能数据和索引。性能一点也不奇怪。MySQL不想使用索引userId
,因此强制使用时,性能会下降。请看我的答案,看一个应该很有效的索引。@TimBiegeleisen我支持你的警告。但我不确定你是否读过我在答案下的评论。如果我没有明确地说出索引,那么查询将超时,它将永远不会返回。它的性能更差。所以,你可以在没有“使用索引”字段的情况下考虑我的问题。主要问题仍然有效。谢谢你的回答。这是真正的解释,并提供了更多的见解。另外,对于您关于表中列数的问题:是的,表中有更多列。我已经更新了这个问题。@Shnkc-因为表中有更多的列,加上您使用了*
(SELECT*
),蒂姆关于“覆盖”的评论不适用。