【MySQL10】进阶篇 | 索引_#1

一、前置环境准备

本次索引实验环境:Linux 环境安装好 MySQL,环境就绪。

二、索引概述

2.1 索引是什么

索引(index)是帮助 MySQL 高效获取数据的数据结构

举个查询示例

sql

sql 复制代码
select *from user where age = 45
  1. 数据表没有索引 :执行查询需要进行全表扫描,查询性能极差
  2. 数据表建立索引(例如二叉树结构):经过几次匹配即可定位目标数据,检索效率大幅提升

2.2 索引优缺点

优点
  1. 大幅加快数据查询速度,降低磁盘 IO 消耗
  2. 借助索引完成排序,减少排序开销、降低 CPU 资源占用
缺点
  1. 索引本身占用磁盘存储空间(日常开发该开销基本可以忽略)
  2. 数据表新增、修改、删除的时候,需要同步维护索引结构,降低增删改的执行速度

三、MySQL 索引底层数据结构

索引是在存储引擎层实现,不同存储引擎支持的索引结构不一样

3.1 四类主流索引结构

  1. B+Tree 索引(最常用、默认索引)
  2. Hash 索引
  3. R‑tree 空间索引
  4. Full‑text 全文索引

3.2 各存储引擎支持清单

  1. InnoDB:B+Tree 索引
  2. MyISAM:B+Tree、R‑tree、全文索引
  3. Memory:B+Tree、Hash 索引

创建索引不指定类型时,MySQL 默认选用 B+Tree 索引,下面重点解析 InnoDB 的 B+Tree

3.3 树结构演进:二叉树 → 红黑树 → B‑Tree → B+‑Tree

  1. 二叉树、红黑树:海量数据场景下树的层级过高,搜索耗时变长,不适合作数据库索引

  2. B‑Tree(多路平衡查找树)

  3. B+‑Tree(InnoDB 索引底层)

    1. 所有行数据 / 主键 key 全部存放在叶子结点
    2. 全部叶子节点依靠指针组成单向链表,方便范围查询
    3. 非叶子结点只存储索引键值,不存储完整行数据
    4. 所有数据存储在磁盘「页 / 块」当中

InnoDB 存储层级关系:表空间 → 段 → 区 → 页 → 行

3.4 Hash 索引原理

  1. 通过哈希算法,把索引键换算成哈希值,映射至哈希表对应的槽位存储
  2. Hash 冲突:多个键值计算之后指向同一个槽位,一般使用链表法解决冲突
Hash 索引特性
  • 仅支持等值查询,不能用于范围检索
  • 无法借助索引完成排序操作
  • 查询速度极快,大多一次寻址即可命中

InnoDB 自带自适应哈希索引:引擎在运行期间,会根据 B+Tree 索引的访问情况,自动构建 Hash 索引优化热点查询

3.5 为什么 InnoDB 优先选用 B+Tree 而不选择其他结构

  1. 对比二叉树:B + 树分支多、树高度低,磁盘 IO 次数更少,搜索效率更高
  2. 对比普通 B‑Tree:B‑Tree 非叶子节点存放行数据,单个节点存放的索引键变少;海量数据场景树高度飙升,性能下降;B + 树非叶子结点只存主键,节点可以存放大量索引 key,树层级极低
  3. 对比 Hash 索引:B+Tree 支持范围查找、索引排序、前缀匹配,适配绝大多数业务场景

四、InnoDB 索引分类

4.1 按照索引功能划分

表格

索引类型 说明 约束 关键字
主键索引 数据表主键建立索引 一张表只能 1 个 PRIMARY
唯一索引 索引字段数值不可重复 一张表可创建多个 UNIQUE
全文索引 检索文本关键词,而非等值比对 一张表可创建多个 FULLTEXT

4.2 按索引存储形式划分(InnoDB 核心概念)

(1)聚集索引(聚簇索引)
  • 索引结构叶子节点直接存放完整行数据
  • InnoDB 强制一张表必须有且仅有一个聚簇索引

聚簇索引选定优先级

  1. 手动设置的主键,优先作为聚集索引
  2. 无主键,则选取第一个唯一非空索引
  3. 没有合适索引,InnoDB 自动生成隐藏 row_id 充当聚集索引
(2)二级索引(普通索引 / 辅助索引)

索引叶子结点只存储主键 ID,不存储整行数据

4.3 回表查询原理

举个案例:user 表主键 id、name 建立普通二级索引

sql

sql 复制代码
select *from user where name = 'Arm';
  1. 在 name 二级索引 B + 树查到叶子结点保存的主键 id
  2. 使用 id 再去聚集索引 B + 树,读取完整行数据 该过程就叫做回表查询

4.4 案例:两条 SQL 效率对比

sql

sql 复制代码
-- 语句1
select *from user where id = 10;
-- 语句2
select *from user where name = 'Arm';
  • 语句 1:id 为主键聚集索引,直接读取叶子结点行数据,一次索引查找
  • 语句 2:name 属于二级索引,需要先查到主键 id、再回表检索,两次 B + 树查询,速度慢于主键查询

4.5 InnoDB B+Tree 索引树高度推算

前提条件

  • InnoDB 一页大小默认 16KB,一行数据 1KB,一页存放 16 行记录
  • bigint 主键占用 8 字节;子节点指针占用 6 字节

设非叶子节点 key 数量为 n

\(n\times8 + (n+1)\times6=16\times1024\) 计算得出 n ≈ 1170

  1. 树高为 2:可存放 1170 * 16 条数据
  2. 树高为 3:可存放 1170 * 1170 *16,量级足够支撑日常业务,因此 InnoDB 索引树高度大多维持在 3 层

五、索引实操 SQL 语法

5.1 基础命令

sql

sql 复制代码
-- 创建索引
CREATE [UNIQUE | FULLTEXT] INDEX index_name ON table_name (index_col_name,...);

-- 查看表全部索引
SHOW INDEX FROM table_name;

-- 删除索引
DROP INDEX index_name ON table_name;

5.2 实战练习(tb_user 数据表)

  1. name 字段允许重复,创建普通单列索引

sql

sql 复制代码
create index idx_user_name on tb_user(name);
  1. phone 手机号唯一非空,建立唯一索引

sql

sql 复制代码
create unique index idx_user_phone on tb_user(phone);
  1. 建立 (profession, age, status) 联合索引

sql

sql 复制代码
create index idx_user_pro_age_sta on tb_user(profession, age, status);
  1. email 字段普通索引优化查询

sql

sql 复制代码
create index idx_user_email on tb_user(email);
  1. 查看 tb_user 所有索引

sql

sql 复制代码
show index from tb_user;
相关推荐
OceanWaves19931 小时前
mysql 5.7.29 主从同步配置
数据库·mysql·adb
molaoye1 小时前
win10下切换MySQL版本
数据库·mysql
丁引2 小时前
《数据清洗的艺术:如何用20行核心逻辑优雅地删除无标签图片》
前端·数据库·python
雨辰AI2 小时前
K8s 数据库 Secret 加密实战|密码明文漏洞彻底修复,等保密评双合规(金仓 / 达梦双库适配)
数据库·容器·kubernetes
c238562 小时前
MySQL 基础用法(下):查询进阶与核心特性
android·c语言·c++·mysql
XR1234567882 小时前
学校图书馆网络改造,方案谁更优?
网络·数据库·php
梦想的旅途22 小时前
企业微信自动化:自动发送文本、图片、文件
前端·数据库·microsoft
IvorySQL3 小时前
PostgreSQL 日报|复制槽泄漏修复(8 月 6 日)
数据库·postgresql
XWalnut3 小时前
MySQL入门到精通
数据库·mysql