B 树 & B+树
B 树:平衡的多叉查找树,每个节点都包含数据,在任意节点匹配上就返回数据,找不到就返回空指针。
B+树:
- 关键字全部存储在叶子节点上,且叶子节点本身根据关键字自小而大顺序连接。
- 非叶子节点可以看成索引部分,节点中仅含有其子树(根节点)中的最大(或最小)关键字。
- 有 n 棵子树的节点含有 n 个关键字(也有认为是 n-1 个关键字)。
B+树的查找过程,在非叶子节点上的关键字等于给定值,并不终止,而是继续沿着指针直到叶子节点位置。因此在 B+树,不管查找成功与否,每次查找都是走了一条从根到叶子节点的路径。
B+树效率
InnoDB 引擎存储数据的时候以页为单位,一页就是一节点。
每个节点的默认大小是 16KB,一个指针的大小是 6 个字节,主键占用 8 个字节,
一个节点大概有 (161024)/(6+8)=1170 个指针,
当表中一条记录 1KB,单个叶子节点可以存储 16 条数据,
即树高度为 2 时能关联 117016=18720 条数据,当高度为 3,能关联 1170117016=21902400 条数据。
索引
索引是有结构的数据,这些数据结构以某种方式引用(指向)数据,MySQL 的索引使用 B+树的数据结构。
主键索引
InnoDB 叶子节点存行数据;MyISAM 叶子节点是数据的地址指针。
普通索引
InnoDB 叶子节点存主键值;MyISAM 叶子节点是数据的地址指针。普通索引查询到叶子节点主键值,用主键去主键索引查数据,这就是回表查询。
聚集索引
索引顺序和数据的顺序一致,如果索引相邻,对应数据也相邻存放。InnoDB 主键索引就是聚集索引,聚集索引将数据与索引放一起,索引结构的叶子结点保存了行数据,聚集索引有且仅有一个。
- 有主键,主键索引就是聚集索引;
- 无主键,第一个唯一索引(UNIQUE)为聚集索引;
- 无主键、唯一键,InnoDB 会生成一个隐式主键(rowid)作为聚集索引列。
索引查询过程:
- where id = 14:主键索引树中找到对应叶子节点,获得行数据;
- where Name = ‘xx’:
- 辅助索引树中检索 Name,到达其叶子节点获取对应的主键。
- 再用主键在主键索引树找到对应叶子节点,获得行数据。
非聚集索引
索引逻辑顺序和磁盘中数据的物理顺序不一致。
覆盖索引
查数据时,select 的列刚好是复合索引中涉及的字段,这样能直接返回数据,避免回表,extra 中 Using Index 说明使用了覆盖索引。
最左匹配原则
覆盖索引要求查询字段的顺序与复合索引从左到右的顺序一致才行。
索引条件下推
当存在索引列条件判断时,将条件判断从 MySQL 服务器向下传递给存储引擎,减少 IO 次数,extra 中 Using index condition 说明使用了索引条件下推。
创建索引
普通索引
1 | -- 将 user 表 user_name 列设为索引 |
唯一索引
1 | create unique index idx_user_name on user(user_name); |
复合索引
1 | create index idx_user_composite_index on user(user_name, email(7)); |
索引失效
- 用 OR 查询;
- 违背最左匹配原则;
- like 以 % 开头;
- 发生类型转换;
- where 中索引列有运算;
- where 中索引列使用了函数;
- 如果 MySQL 觉得全表扫描更快时(数据少);
OR
- 如果条件中有 OR,只要其中一个条件没有索引,其他字段有索引也不会使用。
- 如果条件中的字段都有索引,但是 OR 多个字段都需要全表扫描,因此还是会 走全表扫描 或者 全索引扫描;也就是说如果其他字段不符最左前缀原则,但是都是覆盖索引的值,因此走一次全索引扫描
案例
- where c1=1 OR c2=2 改成 where c1=1 UNION ALL where c2=2
- where id=1 OR id=2 改成 where id in (1,2)