mysql复合索引列顺序和性能

wnvonmuf  于 2021-06-20  发布在  Mysql
关注(0)|答案(2)|浏览(535)

我有一个大约500000行的表,我正在测试它的两个复合索引。第一个索引按列的顺序放在最后,第二个索引则按相反的顺序。
我不明白的是,为什么第二个索引提供了更好的性能,与第一个查询的889行相比,第二个索引估计要扫描30行,因为我觉得第二个索引不能正确使用,因为order by列不是最后一个。有人能解释为什么会这样吗?如果两者都存在,mysql更喜欢第一个索引。
请注意,第二个解释将可能的\u键列为null,但仍然列出所选的键。
1) 第一个索引

ALTER TABLE user ADD INDEX test1_idx (city_id, quality);

(基数12942)

EXPLAIN SELECT * FROM user u WHERE u.city_id = 3205 ORDER BY u.quality DESC LIMIT 30;
+----+-------------+-------+--------+---------------+-----------+---------+----------------+------+-------------+
| id | select_type | table | type   | possible_keys | key       | key_len | ref            | rows | Extra       |
+----+-------------+-------+--------+---------------+-----------+---------+----------------+------+-------------+
|  1 | SIMPLE      | u     | ref    | test1_idx     | test1_idx | 3       | const          |  889 | Using where | 
+----+-------------+-------+--------+---------------+-----------+---------+----------------+------+-------------+

2) 第二个索引(相同字段的顺序相反)

ALTER TABLE user ADD INDEX test2_idx (quality, city_id);

(基数7549)

EXPLAIN SELECT * FROM user u WHERE u.city_id = 3205 ORDER BY u.quality DESC LIMIT 30;
+----+-------------+-------+--------+---------------+-----------+---------+----------------+------+-------------+
| id | select_type | table | type   | possible_keys | key       | key_len | ref            | rows | Extra       |
+----+-------------+-------+--------+---------------+-----------+---------+----------------+------+-------------+
|  1 | SIMPLE      | u     | index  | NULL          | test2_idx | 5       | NULL           |  30  | Using where | 
+----+-------------+-------+--------+---------------+-----------+---------+----------------+------+-------------+

更新:
第二个查询在实际场景中执行得不好,而第一个查询则如预期的那样执行得很好。我仍然很好奇为什么mysql explain会提供如此相反的信息。

pgky5nke

pgky5nke1#

explain中的行只是mysql认为必须检查以产生结果的行数的估计。
我记得读过一篇来自percona的PeterZaitsev的文章说这个数字可能非常不准确。因此,不能简单地根据这个数字来比较查询效率。
我同意你的看法,第一个索引在正常情况下会产生更好的结果。
您应该注意到,第一个explain中的type列是ref,而第二个explain中的index是ref。ref通常比索引扫描好。正如您所提到的,如果两个键都存在,mysql会选择第一个键。

yzuktlbb

yzuktlbb2#

我猜您的数据类型city\u id:mediumint 3字节质量:smallint 2字节
据我所知,为了

SELECT * FROM user u WHERE u.city_id = 3205 ORDER BY u.quality DESC LIMIT 30;

第二个指标(质量、城市标识)不能得到充分利用。因为order by是范围扫描,只能对索引的最后一部分进行扫描。
第一个索引看起来非常适合。我猜有时候mysql不是那么聪明。可能目标城市id的数量会影响mysql决定使用哪个索引。
你可以试试关键词

FORCE INDEX(test1_idx)

相关问题