abc 联合索引查 bc 走不走索引 我觉得按照最左前缀匹配不走,可是面试官说走,说看看 MySQL 内部优化啥的,有没有大佬解答一下
1
find 2020-03-24 08:38:17 +08:00 via iPhone
不走
|
2
Guozi1989 2020-03-24 08:39:43 +08:00
印象中是不走的 坐等大佬解答
|
3
OysterQAQ 2020-03-24 08:39:48 +08:00 via iPhone
索引下推
|
4
2379920898 2020-03-24 08:40:27 +08:00
前缀索引 了解下
|
5
dilu 2020-03-24 08:47:39 +08:00 1
不走
假设列 a:1 2 3 4 5 6 列 b: a b c d e f 列 c: X Y Z W T 以 abc 为维度建立联合索引,真实的索引是这样的 (1a) (1b) ... (4a) .... (1aW) (1aT) .... 并且 B 树数第一层节点存储与内存中 |
6
xiaxiaocao 2020-03-24 08:51:21 +08:00 1
看怎么定义"走不走"了,非前缀匹配的情况下,MySQL 虽然无法直接用联合索引定位,但是可以全部扫描索引,也算是一种使用吧,总比扫表要好。
|
7
qloog 2020-03-24 09:00:51 +08:00
必然不走
|
8
labulaka521 2020-03-24 09:01:47 +08:00 via Android
abc ab a 的走
|
9
skymei 2020-03-24 09:05:57 +08:00
前缀原则,不走
|
10
baozijun 2020-03-24 09:18:02 +08:00
不走
|
11
xiaxiaocao 2020-03-24 09:23:29 +08:00
我再回复一次吧,我想面试官可能要问的是类似覆盖索引这种情况,不一定是用索引树直接定位,但是可以扫描整个索引,这种也算"用到索引"了
|
12
xkeyideal 2020-03-24 09:26:28 +08:00
B+树走最左匹配
|
13
ic2y 2020-03-24 09:31:04 +08:00
|
14
baozijun 2020-03-24 09:32:43 +08:00
abc,如果 a,b,c 都有索引的话,即 idx_a_b_c,也就是索引按照 a->b->c 的排序方式形成 B+树,可以使用 a and b and c,依次走 a b c 的索引. 如果只是 a c 不走 b 的话只走 a 的索引,因为 a 值符合条件的话会接着走 b,如果没有 b 就没法接着走下去.
|
15
yuhuigreed 2020-03-24 09:39:19 +08:00
最左前缀匹配原则,abc 建索引的时候是基于先 a,然后基于 b 、c 有序的,查询时候想走上索引得也按照这个顺序,bc 是走不上索引的
|
16
fancy111 2020-03-24 09:40:17 +08:00 1
一群人瞎几把猜,跑一次不就知道了?
ABC 索引查 BC 的时候虽然没有用到最左侧索引覆盖,但是还是走的索引。extra 显示是 using where 。 |
17
RRRoger 2020-03-24 09:41:02 +08:00
加个字段 col_reverse, 存 cba [旺柴]
|
18
skymei 2020-03-24 09:47:11 +08:00
SELECT * FROM tbl_name WHERE col1=val1;
SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2; SELECT * FROM tbl_name WHERE col2=val2; SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3; 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). |
19
ahsjs 2020-03-24 09:53:06 +08:00
避免打脸,explain 跑一次,b,c type 为 ALL 明细全表了,还叫用索引?
|
20
dovme 2020-03-24 09:57:23 +08:00
这个代表走了还是没走?
https://sm.ms/image/PKq9yu8QGxtv7s3 |
21
gssong OP @fancy111
可是 Using where: 仅仅表示 MySQL 服务器在收到存储引擎返回的记录后进行“后过滤”( Post-filter )。 不管 SQL 语句的执行计划是全表扫描( type=ALL)或非唯一性索引扫描( type=ref) |
22
raysonlu 2020-03-24 10:00:06 +08:00
项目实践中发现,你的搜索条件只有 ABC 的时候,你怎么写顺序都没问题,没有什么最左原则匹配,但如果出现了一个条件 D 后,就不一定了,有时候 BCD 走索引,有时候不走,其实这些都是 MYSQL 解析语句的时候有个步骤是优化语句,看你有无开这个,尽管开了也看它是否人工智能(zhang)帮你优化到尽量用索引,这视乎你的语句复杂度和建立的索引种类,2200 年了,MYSQL 简单的优化还是有的。
|
24
gssong OP @xiaxiaocao 我觉得可能是理解错面试官意思了,他可能问的索引包括这个联合索引之外的索引
|
26
xsm1890 2020-03-24 10:14:31 +08:00
最左前缀原则
|
27
fancy111 2020-03-24 10:14:32 +08:00
@gssong 是的,所以这只是文字游戏,实际上没有用到我们说的索引,只是有可能优化得好查询的时候不是全表,而是之前留下的缓存表。
|
28
littlewing 2020-03-24 10:18:01 +08:00
走索引,但是不走索引
|
29
littlewing 2020-03-24 10:18:40 +08:00
@littlewing 顺序扫描索引,你可以说是走了,也可以说是没走。这样玩文字游戏的面试官直接扇他巴掌
|
30
opengps 2020-03-24 10:20:19 +08:00
回归下索引本身,想想大字典,因为找了 a 才能找到 b,然后才能找到 c,所以不从头开始的索引都没法使用
|
31
pangsq 2020-03-24 10:23:32 +08:00
explain 一把试试。
1. 用的 mysql 5.6.40 ,innodb 2. create table abcd (a varchar(255), b varchar(255), c varchar(255), d varcahr(255)); 3. alter table abcd add index abc(a,b,c); 4. explain select a,b from abcd; # using index 5. explain select b,c from abcd; # using index 6. explain select c,d from abcd; # null |
32
EmdeBoas 2020-03-24 10:24:34 +08:00 1
@dovme 走了,因为二级索引里面已经包含了所有要的字段数据,所以去扫二级索引的树,不用回表;你改一下表结构,新增一些字段结果就不同了,不会命中索引
|
33
baozijun 2020-03-24 10:28:55 +08:00
我错了...看了下文档,发现只用 bc 的话还是会遍历索引 叶子节点进行查找,找到了 b 节点会顺着往下找到 c,所以还是走了索引. @dovme 我感觉 联合索引不用加上主键,因为默认生成的主键(聚簇)索引已经覆盖了.
|
35
gssong OP 表中有 abc 三个字段,都是 int 类型,执行出来 type=index extra 为 Using where; Using index
表中有 abcd 四个字段,都是 int 类型,执行出来 type = all extra 为 Using where |
37
xman99 2020-03-24 10:40:37 +08:00
包含 a 的话走, 如果是 innodb 引擎,b 存在普通二级索引, 也可以使用到索引的。abc 联合索引,需要包含 a 字段才会生效的
|
40
awanganddong 2020-03-24 11:05:56 +08:00
联合索引,给我感觉就是多字段联合排序,先按 A 排,再按 B 排。但是实际上,这个问题比较复杂,必须由示例而定,毕竟查询优化器会选择,如果工作上遇到还是 explain 一波。
有些跑题了 |
41
jamesz 2020-03-24 11:49:06 +08:00 via iPhone
索引跳跃扫描算法可以不走前缀
|
42
qW7bo2FbzbC0 2020-03-24 12:09:24 +08:00
如果 A 是主键的话,可以走索引,如果不是,不可
|
43
gy123 2020-03-24 12:21:57 +08:00
根据 select 字段决定,如果查字段只有索引字段,则可能走,因为不需要回表直接遍历索引树即可,避免查询查询主表中大量数据,其实还是看内部优化器
|
44
Jooooooooo 2020-03-24 12:47:13 +08:00
答案是不走
只查 bc 不需要回表也能叫走索引吗? 是这么定义的吗? |
45
cholerae 2020-03-24 13:04:53 +08:00
有可能走啊,mysql 8.0 有 index skip scan 。
|
46
xiaowangge 2020-03-24 13:16:19 +08:00
MySQL 8.0 doc https://dev.mysql.com/doc/refman/8.0/en/multiple-column-indexes.html
SELECT * FROM tbl_name WHERE col1=val1; SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2; SELECT * FROM tbl_name WHERE col2=val2; SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3; 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). 如果在(col1,col2,col3)上存在索引,则只有前两个查询使用该索引。 第三和第四个查询确实涉及索引列,但不使用索引来执行查找,因为(col2)和(col2,col3)不是(col1,col2,col3)的最左前缀。 |
47
nekoneko 2020-03-24 14:48:39 +08:00
走了也没走
如果有 abcd 列,查 bc 用 bc 做 where 条件,那么会遍历索引 如果查 bcd 列,用 bc 做 where 条件,那么不走索引 |
48
cxshun 2020-03-24 16:47:36 +08:00 6
要分几种情况:
1 、假设你的表就 a,b,c 三个字段,那么你建了(a,b,c)这样的索引,然后按 b,c 搜索(即 select * from t where b = xx and c = xx ),这样会走 为什么走索引呢,主要是因为查询的所有字段在索引中都可以找到,根本就不需要回表,直接覆盖索引了 2 、假设你的表有 a,b,c,d 四个字段,那么你建了(a,b,c)这样的索引,然后按 b,c 搜索(即 select * from t where b = xx and c = xx ),那么此时就不会走索引了,因为走了索引也需要回表,对性能优化没太大用处,当然,你可以把索引改为(a,b,c,d ),然后又可以命中了。 |
49
vindurriel 2020-03-24 17:47:37 +08:00 via iPhone
即使 mysql 有优化 做功能也不应该依赖这个 老老实实建好索引才是正确的选择 否则换个 db 甚至换个版本就出问题
|
50
lucky215 2020-03-24 18:21:26 +08:00
@cxshun 说的靠谱
再补充下,如果在 a,b,c,d 四个字段的情况下,select b,c from t where b = xx and c = xx,也是会走索引的,因为还是覆盖到了 |
51
CRVV 2020-03-24 18:22:02 +08:00
这个问题经常有人问,标准答案是不走。
至于到底走不走,必须要说清楚是哪个数据库,哪个版本,表里有多少行,每个字段是什么类型,每个字段的取值范围。基本上没人知道这些问题的答案,所以 PostgreSQL 的文档说的是 This index could in principle be used for queries that have constraints on b and/or c with no constraint on a — but the entire index would have to be scanned, so in most cases the planner would prefer a sequential table scan over using the index. 拿文档来回答这个问题,那就是可以走索引( This index could in principle be used ) 具体来说,假设三个字段里,a 是性别,b 是年龄,c 是身高。 你可以把 select * from table where b = 18 and c = 170 拆开成 select * from table where a = '男' and b = 18 and c = 170 union all select * from table where a = '女' and b = 18 and c = 170 这样就可以走索引了,很有可能比不走索引要快。 数据库可以帮你这样优化,但到底会不会优化呢? in most cases the planner would prefer a sequential table scan. https://www.postgresql.org/docs/12/indexes-multicolumn.html |
52
1424659514 2020-03-24 18:22:11 +08:00
@cxshun 老哥牛批
|
53
mitoop 2020-03-25 00:18:19 +08:00
@cxshun 正解 同意 @vindurriel 的说法 老老实实建立好索引 即使用了覆盖索引 还是会 type=index 比 type=all 好那么一点 如果就 abc 三个字段 和 type=all 几乎一样了
|
54
xiaowangge 2020-03-28 19:46:28 +08:00
|