主索引与索引的查询性能

时间:2019-07-18 08:43:02

标签: mysql performance innodb

我有一个关于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 ,是created字段ASC上的另一个键。

tableA是一个很大的表,它包含数百万行。

我在此表上运行的查询是:

标识为1234的用户在此表中有150万条记录。我想获取其最新的100行。为了实现这一点,我有2个不同的查询:

查询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;

由于id的{​​{1}}字段是自动递增的,因此保留了最新的条件。这两个查询返回相同的结果。但是,存在巨大的性能差异。

查询计划是

tableA

我了解到查询1上有一个排序操作。在每个查询中,使用的索引为+----------+-----------------------------------------------+-------------------------------+------+---------------------------------------+ | 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 | +--------+-------------+ 。但是为什么在查询2中不使用排序?主索引如何影响?

MySQL 5.7

编辑:表上有更多列,我从上面的表定义中提取了它们。

2 个答案:

答案 0 :(得分:1)

  

由于tableA的id字段是自动递增的,因此保留了最新的条件。

这通常是有效的声明。

WHERE userId=1234 ORDER BY created DESC LIMIT 100

需要此“复合”索引:(userId, created)。这样,无论表大小或该用户的行数如何,它都只会命中100行。

同样的道理

WHERE userId=1234 ORDER BY id DESC LIMIT 100;

即它需要(userId, id)。但是,在InnoDB中,当您说INDEX(x)时,它会默默地附加在PRIMARY KEY列上。这样您就可以有效地获得INDEX(x,id)。这就是为什么您的普通INDEX(userId)运作良好的原因。

EXPLAIN很少(如果有的话)考虑到LIMIT。这就是两个查询的“行”均为“ 2.5M”的原因。

如果您删除了INDEX(userId)提示,则第一个查询可能(也可能没有)使用了USE INDEX。选择取决于表中有userId = 1234的百分比。如果小于约20%,则将使用索引。但是它会在二级索引和数据之间来回跳动-全部进行150万次。如果超过20%,则只需读取所有“百万”行,而忽略不适用的行,就可以避免跳动。

注意:Q1的内容仍将读取至少150万行,对其进行排序(“使用文件排序”),然后剥离所需的100行。但是使用INDEX(userId, created),它可以跳过排序并查看仅100行。

我无法解释“唯一索引扫描”,而没有看到SHOW CREATE TABLE和未注释的EXPLAIN。 (EXPLAIN FORMAT=JSON SELECT...可能会提供更多见解。)

答案 1 :(得分:0)

在第一个查询中,您强制MySQL使用userId索引,结果是第一个查询的性能比第二个查询差。 通常,强制数据库使用索引是不好的。在这里使用的最佳索引是:

CREATE INDEX idx ON tableA (userId, created, id);   -- perhaps id can be omitted if on InnoDB

此索引将使WHERE子句非常严格,也可以用于created子句中的ORDER BY进行排序。该索引还完全覆盖了SELECT *,这意味着MySQL不需要寻找其他数据的聚集索引。