Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 主索引与索引的查询性能_Mysql_Performance_Innodb - Fatal编程技术网

Mysql 主索引与索引的查询性能

Mysql 主索引与索引的查询性能,mysql,performance,innodb,Mysql,Performance,Innodb,我有一个关于mysql的表和两个性能完全不同的查询。我已经提取了查询计划,但我无法完全理解性能差异背后的原因 下表: +-------------+----------------------------------------------+------------------------------------+ | TableA | |

我有一个关于mysql的表和两个性能完全不同的查询。我已经提取了查询计划,但我无法完全理解性能差异背后的原因

下表:

+-------------+----------------------------------------------+------------------------------------+
|   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*
),蒂姆关于“覆盖”的评论不适用。