Bootstrap

MySQL面试学习笔记(全)

索引篇

1. 索引底层数据结构和算法

1.1 索引概述

索引是一种加快查询和检索数据的数据结构,其本质就可以看作是排好序的数据结构。如果没有走索引,查询数据将会走全表扫描。

索引底层的数据结构有很多种类型,常见的索引数据结构有:B树、B+树、hash、红黑树;再MySQL中,无论是innodb还是m'yisam存储引擎,都是使用的B+树作为索引的结构;

1.1.1 BST二叉树搜索

1.1.2 红黑树(二叉平衡树)
  1. 定义:红黑树是一种二叉排序树,即满足左子树结点值小于根节点值小于右子树结点值。同时,与普通二叉排序树(BST)相比,红黑树的每个结点还带有颜色属性,颜色只能是红色或黑色。
  2. 性质
    • 根结点是黑色的。
    • 叶结点(外部结点、NULL结点、失败结点)均是黑色的。
    • 不存在两个相邻的红色结点,即红色结点的父结点和孩子结点均是黑色的。
    • 对每个结点,从该结点到任一叶结点的简单路径上,所含黑结点的数目相同。

1.1.3 B树

1.1.4 B+树

B树和B+树的区别:

  1. B树的所有结点既存放键( key ),也存放数据( data),但是B+树只有叶子节点存放key和data,非叶子节点只存放key。
  2. B树的叶子节点是独立的;B+树的叶子节点有一条链表指向相邻叶子节点。
  3. B树的检索过程不稳定,可能还没有到达叶子节点,检索就结束了。但是B+树每次检索数据都要检索到叶子节点,查找比较稳定。
  4. B树在进行范围查询时,首先找到要查找的下限,然后对B树进行中序遍历,直到找到查找的上限;但是B+树的范围查询只需要对链表进行遍历即可。
1.1.5 hash索引

哈希索引就是采用一定的hash算法,将键值换算成新的hash值,直接映射到对应的槽位上,然后存储在hash表中。(但是要注意hash冲突)

缺点:不支持范围索引,仅能满足=, in等。

1.2. Innodb&MyISAM在存储结构的区别

在MySQL中,MyISAM引擎和InnoDB引擎都是使用B+树作为索引结构,但是两者实现的方式不太一样。(聚集索引和非聚集索引)。

  1. MyISAM存储引擎中,B+叶子节点的data存放的是数据记录的地址。在检索数据时,首先按照B+树去检索数据,取出data域的值,然后以data域的值为地址读取相应的数据记录。这里被称为非聚集索引
  2. Innodb存储引擎中,其数据文件本身就是索引文件。相比MyISAM,索引文件和数据文件是分开的,其数据文件本身就是按照B+树组织的一个索引结构,树节点的data域保存了完整的数据记录。这个key就是表的主键,这被称为聚簇索引

三层的B+树可以至少存储2000w+的数据。超过两千万就建议分库分表。

MyISAM存储引擎中索引文件(MYI, MyISAM Index)和数据文件(MYD, MyISAM Data)是分离的。

MyISAM存储引擎无论是主键索引还是非主键索引,叶子节点存储的都是索引列+数据的地址值。

InnoDB只有一个ibd(Innodb data)文件,数据文件本身就是索引文件。叶子节点直接存放索引和数据,而不是存放索引和地址。

聚集索引 - 叶子结点包含了完整的数据记录,比如Innodb的主键索引就是聚集索引

非聚集索引 - 叶子节点只包含索引和数据地址,比如MyISAM的主键索引就是非聚集索引

1.3. 索引分类

我们可以按照四个角度来分类索引。

  • 按「数据结构」分类:B+tree索引、Hash索引、Full-text索引
  • 按「物理存储」分类:聚簇索引(主键索引)、二级索引(辅助索引)
  • 按「字段特性」分类:主键索引、唯一索引、普通索引、前缀索引
  • 按「字段个数」分类:单列索引、联合索引

1.4 索引为什么使用b+?

1.这种结构胖矮!矮的作用就是减少io操作,因为每次进行行的跳转就会涉及到io操作;胖是一个层级可以存储很多数据,3层机构就可以存储千万级别的数据;

2.所有叶子节点都在同一层;

3.所有叶子节点之间通过双向链表进行连接;

1.5 聚簇索引与普通索引的区别?

聚簇索引:1.非叶子节点存储的是id和页号;2.叶子节点存储的是行数据;

普通索引:1.非叶子节点存储的是id,索引列和页号;2.叶子节点存储的是id和索引列;

1.6 索引的一些现象和行为?

索引覆盖:是指需要查询的字段全都被索引包含;

回表查询:在普通索引的情况下,查询的字段要多于我们的索引字段,此时查找到id后回到聚簇索引在查找行数据;

索引下推:能使用索引的情况下MySQL会尽量使用索引;即使不满足最左前缀原则也可能会使用;5.6之前的版本是根据索引找到一条数据行,检索数据其他的过滤条件;而现在是现在引擎层判断完全部的条件之后再将结果返回;

索引跳跃:MySQL8之后的索引查询,即使不满足最左匹配原则,MySQL可能优化后还是走的索引;

那种情况不会发生索引跳跃:

1.不是单表查询,而是多表关联;

2.select中的字段包含非索引字段;

3.sql中带有group by或者distinct关键字;

1.7 索引失效情况:

不满足最左前缀;

对索引列进行了运算;

mysql认为使用索引效率低于全表扫描;

1.8 索引建立原则:

1.单个表的索引数量不要太多:

因为每个索引对应一个B+树,并且叶子节点存储了索引的全量数据,一旦索引的数量多,那么就会占用大量的磁盘空间;

再查询之前会对索引的成本进行计算,一旦索引过多,计算的次数就多,也可能会浪费性能;

2.经常出现在where后面的字段可以建立索引

3.order by 和group by后面的字段可以建立索引

4.频繁更新的字段不适合建立索引

因为索引要保证按照索引列的值进行排序,所以一旦索引数据字段频繁更新,那么为了保证索引的顺序,就要频繁的挪动索引列再索引中的位置;

5.对于重复值较少的列建立索引;

1.9 最左前缀匹配的原则(联合索引):

再遇到范围查询(如<、>)就会停止匹配,也就是范围查询的字段是可以走索引的,但是范围查询后面的字段是无法使用联合索引的。

注意:对于>=、<=、between and以及like ‘具体值%’这种存在等值条件的范围查询,等值条件的那部分数据是可以走联合索引的,通过explain关键字分析的索引是相当于走的联合索引;

1.10 为什么B+树存储千万级的数据只需要三到四层高度?

InnoDB存储引擎中页的大小为16KB,而一般数据的主键是INT(占用4字节)或者BIGINT类型(占用8字节),指针类型也是4字节或者8字节,也就是说一个页(B+树中的一个节点)中大概存储16KB/(8B+8B)=1000个键值,这里是计算的非叶子节点;

我们再看叶子节点,假设一行数据的大小为1KB,那么高度为3的B+树可以存放1000*1000*16=16000000条记录。

由此我们可以得出高度为3的B+树可以存储千万条记录。

为什么DBA建议InnoDB必须建主键,并且推荐使用整形的自增主键

  1. 为什么DBA建议InnoDB必须建主键因为InnoDB采用B+树组织数据文件。
  2. 为什么不建议使用uuid作为主键id
    1. 因为字符串比较按照ascii逐个字符比较,效率较慢。
    2. uuid占用空间
  1. 为什么推荐使用自增的主键id:
    1. 页分裂
-- MySQL主键选择
1. 如果指定了主键id,那么就会使用id作为主键
2. 如果没有指定主键id,那么将会使用第一列唯一索引作为主键
3. 如果没有唯一索引,将会生成一个隐藏字段 DB_ROW_ID 作为隐藏主键

2. explain关键字的详细分析

2.1. 2.1 explain执行计划

2.1.1 id

id表示表的执行顺序,有几个select就有几个id。

id列越大,执行优先级越高,id相同就从上到下执行。

2.1.2 select_type
  1. simple:简单查询,查询不包括子查询和union
explain select * from actor where id = 1;

  1. primary:复杂查询中最外层的select的select_typeprimary
  2. subquery:包含在select中的子查询(比如:在select关键词后面的查询),不在from语句中
  3. derived:包含在from字句中的子查询,MySQL会将结果存放在一个临时表,也叫做派生表(derived)
# 关闭mysql5.7新特性对衍生表的合并操作
set session optimizer_switch = 'derived_merge=off';

# 查看执行计划
explain 
select (select 1 from actor where id = 1)
from (select * from film where id = 1) der;

2.1.3. table列

表示explain的一行正在访问哪个表。

当from子句中有子查询时,table列是<derivedN>,表示当前查询依赖 id = N的查询,于是先执行id = N的查询。

2.1.4. type列

这一列表示关联类型或访问类型即MySQL决定如何查找表中的行,查找数据行记录的大概范围。

依次从最优到最差分别为:system > const > eq_ref > ref > range > index > All

  1. const

const表示表中最多只有一行匹配的记录,一次查询就可以找到,常用于使用主键索引或唯一索引的字段作为查询条件。

  1. system

system:system是const的特例,表中只有一行记录的情况下为system。

explain
select * from (select * from film where id = 1) tmp;

  1. eq_ref

当连表查询时,前一张表的行在当前这张表中只有一行数据与之对应。是除了system和const之外最好的join方式,一般用于使用主键或者唯一索引的字段作为连表条件。

简单的select查询不会出现这种type

explain
select * from film_actor
left join film on film_actor.film_id = film.id;

  1. ref

ref:不是使用主键或者唯一索引,而是使用普通索引作为所有条件,查询结果可能会找到多条符合条件的行。

explain select * from film where name = 'film1';

  1. range

range表示对索引列范围查询,比如出现在in()between,<,>=等操作中,使用一个索引检索给定范围的值。

explain select * from actor where id > 1;

  1. index

如果主键索引和二级索引都有全部数据,那么查询全部数据的时候,会走二级索引,因为主键索引叶子节点数据比较多,树太大了。但是如果只有主键索引有全部数据,就会走主键索引

index表示遍历了整颗索引树,一般是扫描整个二级索引,这种扫描不会从索引树的根节点开始快速查找,而是直

;