› MySQL 5.5 Community Server
› MySQL 5.6 Community Server
› Percona Configuration Wizard
› XtraBackup 搭建主从复制
Great Sites on MySQL
› Percona
› MySQL Performance Blog
› Severalnines
推荐管理工具
› Sequel Pro
› phpMyAdmin
推荐书目
› MySQL Cookbook
MySQL 相关项目
› MariaDB
› Drizzle
参考文档
› http://mysql-python.sourceforge.net/MySQLdb.html
gssong
V2EX  ›  MySQL

abc 联合索引查 bc 走不走索引

  •  1
     
  •   gssong · Mar 24, 2020 · 11099 views
    This topic created in 2417 days ago, the information mentioned may be changed or developed.

    abc 联合索引查 bc 走不走索引 我觉得按照最左前缀匹配不走,可是面试官说走,说看看 MySQL 内部优化啥的,有没有大佬解答一下

    56 replies  •  2023-08-26 17:18:39 +08:00
    find
    find
    Mar 24, 2020 via iPhone
    1
    不走
    Guozi1989
    Guozi1989
    Mar 24, 2020
    2
    印象中是不走的 坐等大佬解答
    OysterQAQ
    OysterQAQ
    Mar 24, 2020 via iPhone
    3
    索引下推
    2379920898
    2379920898
    Mar 24, 2020
    4
    前缀索引 了解下
    dilu
    dilu
    Mar 24, 2020❤️1
    5
    不走
    假设列 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 树数第一层节点存储与内存中
    Fistandantilus
    Fistandantilus
    Mar 24, 2020❤️1
    6
    看怎么定义"走不走"了,非前缀匹配的情况下,MySQL 虽然无法直接用联合索引定位,但是可以全部扫描索引,也算是一种使用吧,总比扫表要好。
    qloog
    qloog
    Mar 24, 2020
    7
    必然不走
    labulaka521
    labulaka521
    Mar 24, 2020 via Android
    8
    abc ab a 的走
    skymei
    skymei
    Mar 24, 2020
    9
    前缀原则,不走
    baozijun
    baozijun
    Mar 24, 2020
    10
    不走
    Fistandantilus
    Fistandantilus
    Mar 24, 2020
    11
    我再回复一次吧,我想面试官可能要问的是类似覆盖索引这种情况,不一定是用索引树直接定位,但是可以扫描整个索引,这种也算"用到索引"了
    xkeyideal
    xkeyideal
    Mar 24, 2020
    12
    B+树走最左匹配
    ic2y
    ic2y
    Mar 24, 2020
    13
    baozijun
    baozijun
    Mar 24, 2020
    14
    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 就没法接着走下去.
    yuhuigreed
    yuhuigreed
    Mar 24, 2020
    15
    最左前缀匹配原则,abc 建索引的时候是基于先 a,然后基于 b 、c 有序的,查询时候想走上索引得也按照这个顺序,bc 是走不上索引的
    fancy111
    fancy111
    Mar 24, 2020❤️1
    16
    一群人瞎几把猜,跑一次不就知道了?
    ABC 索引查 BC 的时候虽然没有用到最左侧索引覆盖,但是还是走的索引。extra 显示是 using where 。
    RRRoger
    RRRoger
    Mar 24, 2020
    17
    加个字段 col_reverse, 存 cba [旺柴]
    skymei
    skymei
    Mar 24, 2020
    18
    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).
    ahsjs
    ahsjs
    Mar 24, 2020
    19
    避免打脸,explain 跑一次,b,c type 为 ALL 明细全表了,还叫用索引?
    dovme
    dovme
    Mar 24, 2020
    20
    这个代表走了还是没走?
    https://sm.ms/image/PKq9yu8QGxtv7s3
    gssong
    gssong
    OP
    Mar 24, 2020
    21
    @fancy111
    可是 Using where: 仅仅表示 MySQL 服务器在收到存储引擎返回的记录后进行“后过滤”( Post-filter )。 不管 SQL 语句的执行计划是全表扫描( type=ALL)或非唯一性索引扫描( type=ref)
    raysonlu
    raysonlu
    Mar 24, 2020
    22
    项目实践中发现,你的搜索条件只有 ABC 的时候,你怎么写顺序都没问题,没有什么最左原则匹配,但如果出现了一个条件 D 后,就不一定了,有时候 BCD 走索引,有时候不走,其实这些都是 MYSQL 解析语句的时候有个步骤是优化语句,看你有无开这个,尽管开了也看它是否人工智能(zhang)帮你优化到尽量用索引,这视乎你的语句复杂度和建立的索引种类,2200 年了,MYSQL 简单的优化还是有的。
    ahsjs
    ahsjs
    Mar 24, 2020
    23
    @raysonlu 说的是没有 A 的时候,讨论的应该不是优化这个
    gssong
    gssong
    OP
    Mar 24, 2020
    24
    @xiaxiaocao 我觉得可能是理解错面试官意思了,他可能问的索引包括这个联合索引之外的索引
    gssong
    gssong
    OP
    Mar 24, 2020
    25
    @ahsjs 和楼下的结果 type 是 index
    xsm1890
    xsm1890
    Mar 24, 2020
    26
    最左前缀原则
    fancy111
    fancy111
    Mar 24, 2020
    27
    @gssong 是的,所以这只是文字游戏,实际上没有用到我们说的索引,只是有可能优化得好查询的时候不是全表,而是之前留下的缓存表。
    littlewing
    littlewing
    Mar 24, 2020
    28
    走索引,但是不走索引
    littlewing
    littlewing
    Mar 24, 2020
    29
    @littlewing 顺序扫描索引,你可以说是走了,也可以说是没走。这样玩文字游戏的面试官直接扇他巴掌
    opengps
    opengps
    Mar 24, 2020
    30
    回归下索引本身,想想大字典,因为找了 a 才能找到 b,然后才能找到 c,所以不从头开始的索引都没法使用
    pangsq
    pangsq
    Mar 24, 2020
    31
    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
    EmdeBoas
    EmdeBoas
    Mar 24, 2020❤️1
    32
    @dovme 走了,因为二级索引里面已经包含了所有要的字段数据,所以去扫二级索引的树,不用回表;你改一下表结构,新增一些字段结果就不同了,不会命中索引
    baozijun
    baozijun
    Mar 24, 2020
    33
    我错了...看了下文档,发现只用 bc 的话还是会遍历索引 叶子节点进行查找,找到了 b 节点会顺着往下找到 c,所以还是走了索引. @dovme 我感觉 联合索引不用加上主键,因为默认生成的主键(聚簇)索引已经覆盖了.
    ahsjs
    ahsjs
    Mar 24, 2020
    34
    @pangsq 大佬 d varchar 都打错了,确定试了?
    gssong
    gssong
    OP
    Mar 24, 2020
    35
    表中有 abc 三个字段,都是 int 类型,执行出来 type=index extra 为 Using where; Using index
    表中有 abcd 四个字段,都是 int 类型,执行出来 type = all extra 为 Using where
    aliipay
    aliipay
    Mar 24, 2020
    36
    @gssong 是 index 还是 all 和 select 内容有关的
    xman99
    xman99
    Mar 24, 2020
    37
    包含 a 的话走, 如果是 innodb 引擎,b 存在普通二级索引, 也可以使用到索引的。abc 联合索引,需要包含 a 字段才会生效的
    dovme
    dovme
    Mar 24, 2020
    38
    @EmdeBoas #32 你是对的,我新增一个字段 d,然后还是执行刚才的 sql,没有走索引.
    pangsq
    pangsq
    Mar 24, 2020
    39
    @ahsjs == 见谅,先在 mysql 里跑的后敲在这的,没复制
    awanganddong
    awanganddong
    Mar 24, 2020
    40
    联合索引,给我感觉就是多字段联合排序,先按 A 排,再按 B 排。但是实际上,这个问题比较复杂,必须由示例而定,毕竟查询优化器会选择,如果工作上遇到还是 explain 一波。

    有些跑题了
    jamesz
    jamesz
    Mar 24, 2020 via iPhone
    41
    索引跳跃扫描算法可以不走前缀
    qW7bo2FbzbC0
    qW7bo2FbzbC0
    Mar 24, 2020
    42
    如果 A 是主键的话,可以走索引,如果不是,不可
    gy123
    gy123
    Mar 24, 2020
    43
    根据 select 字段决定,如果查字段只有索引字段,则可能走,因为不需要回表直接遍历索引树即可,避免查询查询主表中大量数据,其实还是看内部优化器
    Jooooooooo
    Jooooooooo
    Mar 24, 2020
    44
    答案是不走

    只查 bc 不需要回表也能叫走索引吗? 是这么定义的吗?
    6ufq0VLZn0DDkL80
    6ufq0VLZn0DDkL80
    Mar 24, 2020
    45
    有可能走啊,mysql 8.0 有 index skip scan 。
    xiaowangge
    xiaowangge
    Mar 24, 2020
    46
    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)的最左前缀。
    nekoneko
    nekoneko
    Mar 24, 2020
    47
    走了也没走
    如果有 abcd 列,查 bc 用 bc 做 where 条件,那么会遍历索引
    如果查 bcd 列,用 bc 做 where 条件,那么不走索引
    cxshun
    cxshun
    Mar 24, 2020❤️6
    48
    要分几种情况:
    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 ),然后又可以命中了。
    vindurriel
    vindurriel
    Mar 24, 2020 via iPhone
    49
    即使 mysql 有优化 做功能也不应该依赖这个 老老实实建好索引才是正确的选择 否则换个 db 甚至换个版本就出问题
    lucky215
    lucky215
    Mar 24, 2020
    50
    @cxshun 说的靠谱
    再补充下,如果在 a,b,c,d 四个字段的情况下,select b,c from t where b = xx and c = xx,也是会走索引的,因为还是覆盖到了
    CRVV
    CRVV
    Mar 24, 2020
    51
    这个问题经常有人问,标准答案是不走。

    至于到底走不走,必须要说清楚是哪个数据库,哪个版本,表里有多少行,每个字段是什么类型,每个字段的取值范围。基本上没人知道这些问题的答案,所以 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
    1424659514
    1424659514
    Mar 24, 2020
    52
    @cxshun 老哥牛批
    mitoop
    mitoop
    Mar 25, 2020
    53
    @cxshun 正解 同意 @vindurriel 的说法 老老实实建立好索引 即使用了覆盖索引 还是会 type=index 比 type=all 好那么一点 如果就 abc 三个字段 和 type=all 几乎一样了
    xiaowangge
    xiaowangge
    Mar 28, 2020
    54
    应该换个更详细的问题,表结格和 explain 分析图:

    参考这个:

    mysql 索引最左匹配原则的理解
    https://www.zhihu.com/question/36996520
    54qyc
    54qyc
    Aug 26, 2023
    55
    @CRVV 但是这适用于 mysql 吗?
    54qyc
    54qyc
    Aug 26, 2023
    56
    @dovme type = index 扫描索引。extra= using index 不用回表因为 abc 二级索引有全部数据。extra= using where 用 where 子句过滤扫描的行。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   5051 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 121ms · UTC 07:05 · PVG 15:05 · LAX 23:05 · JFK 02:05
    ♥ Do have faith in what you're doing.