mysql 官方的文档乱得一匹,找了半天找到了答案。
很多人(包括 OP )觉得不走索引是因为 Mysql 文档这么写的: If an index exists on (col1, col2, col3), only the first two queries use the index. The third and fourth queries do involve indexed columns, but do not use an index to perform lookups because (col2) and (col2, col3) are not leftmost prefixes of (col1, col2, col3). 这里是说 not use an index to perform lookups
另一处在 Skip Scan Range Access 一节是这么写的:
CREATE TABLE t1 (f1 INT NOT NULL, f2 INT NOT NULL, PRIMARY KEY(f1, f2));
INSERT INTO t1 VALUES
(1,1), (1,2), (1,3), (1,4), (1,5),
(2,1), (2,2), (2,3), (2,4), (2,5);
INSERT INTO t1 SELECT f1, f2 + 5 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 10 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 20 FROM t1;
INSERT INTO t1 SELECT f1, f2 + 40 FROM t1;
ANALYZE TABLE t1;
EXPLAIN SELECT f1, f2 FROM t1 WHERE f2 > 40;
To execute this query, MySQL can choose an index scan to fetch all rows (the index includes all columns to be selected), then apply the f2 > 40 condition from the WHERE clause to produce the final result set. 这里提到会使用索引扫描。
所以意思就是会用索引扫描但是不会用索引查找(lookup). 所以索引还有其他用途吗?一会 index scan 一会 use an index to lookup. 还有 use an index to do 其他的吗? 中文里的走索引意思不只指的用索引查询(lookup).
此外:在这个表中聚集索引叶子结点存的是 id, f1, f2 。 联合索引也是存的 f1, f2, id 。这里为啥会扫联合索引而不是聚集索引。这俩索引在这个表下 size 应该是差不多的吧。
(f1,f2)看错了以为是二级索引,没想到文档中定义的是聚集索引。那这个文档仍然也没说明是否走二级索引扫描。
回到标题的问题:假设ab 是二级联合索引, 只where b. 看到兄弟帖子20楼的图上explain 给出的是using index 所以估计还是扫描了联合索引。https://www.v2ex.com/t/655560# 。
这里的前提是:对于 explain output type中有index 以及all 这2种分类,index应该就是不包括聚集索引?而all就是聚集索引扫描又叫做全表扫描?
1
Ericcccccccc 2023-08-26 14:21:39 +08:00
不会, 你简单思考下索引的数据结构, 是怎么被存储/使用就能很快明白, 无法用 b 来索引.
|
2
sunhuawei 2023-08-26 14:53:13 +08:00
楼上应该没仔细看正文。
op 的疑问是:1. 第二个例子中 where f2 > 40 会使用(f1, f2)索引。2. 为什么聚集索引和联合索引差不多,不使用聚集索引。 以我个人拙见,MySQL can choose an index scan to fetch all rows ,指的就是全表扫描,建表语句中 PRIMARY KEY(f1, f2)显性得创建了主键索引,那它就是这张表的聚集索引。所以 where f2 > 40 就会使用且只会使用 PRIMARY KEY(f1, f2),因为没别的索引了。 至于索引查找和索引扫描的区别,这是两种策略,有时单独使用有时相互配合,具体可以问下 chatGPT 。 |
3
Immortal 2023-08-26 14:59:03 +08:00
不会
我记得在高性能 mysql 一书中就有一章讲最左原则来着 |
4
nightfog 2023-08-26 15:37:58 +08:00 via iPhone
“MySQL can choose an index scan to fetch all rows (the index includes all columns to be selected), then apply the f2 > 40 condition from the WHERE clause to produce the final result set”
这段话应该没有走索引得意思,看上去是全表扫。 |
5
hangszhang 2023-08-26 15:42:54 +08:00
你可以简单把索引列的字段看作是 Java 里面的 compareTo 方法里面的比较元素,比如 index(a,b),就是先比较 a 的大小,如果 a 相等,再来比较 b 列。MySQL 也是这么做的,( a,b )存储在 MySQL B+ 树里面就是按照这个顺序存储的,找的时候也是按照二分查找在这棵树里面来找。回到这个 case ,查询条件里面没有 b 的话,就无法比较大小,也就无法使用到这棵 B+树进行搜索,也就无法使用到这个索引
|
6
makelove 2023-08-26 15:58:34 +08:00
很明显不可能,组合索引是二字段组一起排序的,相当于一整个字串,你字串查找也只能开头 xxx% 才能走索引
|
7
LeeSeoung 2023-08-26 16:50:24 +08:00
MySQL 8.0.13 开始支持 index skip scan 这里有例子 楼上说不行的同学可以更新下,但是这个特性也是有使用条件的,具体看这篇文章吧
https://blog.csdn.net/weixin_34677764/article/details/116106524 |
9
me1onsoda 2023-08-26 17:52:57 +08:00
用脚指头想一下,应该是不会。ab 联合索引可能是这样的(1,2),(2,1), b 这一列不是有序的,没法走索引
|
10
est 2023-08-26 18:53:09 +08:00
其实也是可能用的。比如 a 是可以遍历的。你可以在 sql 里把 a 所有的值全部 or 一遍。
|
12
iseki 2023-08-26 19:43:13 +08:00 via Android
可以用到索引,但不是那么简单高效的直接按 B🌳查找,而是更复杂的堆扫描位图扫描。当 planner 认为这样更划算时就会这么做
|
13
sunhuawei 2023-08-26 21:34:38 +08:00
@54qyc #8 目前我收集到的主流说法是:1. 当出现`覆盖索引`的情况时,where f2 也许会使用此联合索引 2. 当 f2 列的值非常唯一(即重复值占比高)时,也许会使用此联合索引,仔细想想确实比全表扫描(即聚集索引)快。
当然,我觉得查询优化器绝非如此简单生硬,应该还有很多文档都没记录的规则。如果是应付面试,我觉得上面两条答案够了。如果真想研究,只有嚼源码这一条路。 |
15
shinyruo2020 2023-08-27 01:47:37 +08:00
其实理论上是可以用到索引的,了解下跳跃索引扫描,利用索引的有序性,就算只有第二列仍然可以利用索引过滤部分数据,只是 mysql 优化器的局限性而已
|
16
ZZ74 2023-08-27 11:41:02 +08:00
看的真捉急,特意注册了来回复。
最左匹配没问题。例子也没问题,官网文档也没问题。 例子中表就两列,组合成主键,select 了所有列的时候选择对主键索引做扫描,就能拿到结果 所以说走了索引,但是又和平时所谓的走索引不同。 所以说走了索引,但是又和平时所谓的走索引不同。 所以说走了索引,但是又和平时所谓的走索引不同。 英文描述也十分清楚 “MySQL can choose an index scan to fetch all rows (the index includes all columns to be selected), then apply the f2 > 40 condition from the WHERE clause to produce the final result set” 在索引包含所有 select 列的情况/前提下(the index includes all columns to be selected) 会选择扫描索引来拿到所有行 MySQL can choose an index scan to fetch all rows 然后才会过滤>40 的拿到最终结果。 至于这种情况下的优化,比如说到的跳跃索引扫描,那要看 mysql 的做法了。 |