MySQL —— Innodb 索引数据结构


MySQL 使用 B+树索引数据结构(因为默认使用 innodb 存储引擎)

  • B树:有序数组 + 平衡多叉树;
  • B+树:有序数组链表 + 平衡多叉树;

不用平衡二叉树或红黑树作为索引

普通二叉树:

  • 二叉树的查找的时间复杂度是 O ( l o g 2 N ) O(log_2N) O(log2N),其查找效率与深度有关,而普通的二叉树可能由于内部节点排列问题退化成链表。例如,按顺序插入一组递增的数值,可能导致树变成一条链表,在这种情况下,树的深度变为 N,查找的时间复杂度退化为 O ( N ) O(N) O(N),这与链表的查找效率相同。这样查找效率就会很低。
    1
     \
      2
       \
        
<think>嗯,用户这次想深入了解MySQL索引的存储结构,看来是个认真钻研技术细节的人。从ta引用的资料来看,已经对B+树、聚集索引等概念有基础了解,现在需要更系统的解析。 用户可能正在做数据库性能优化,或者准备面试。ta引用的三篇资料质量不错,特别是第三篇提到磁盘页16KB设计对树高的影响,这个点很关键。我需要在回答中强化这个计算过程:1170个子节点 * 1170 * 1170 ≈ 1600万数据只需3层,这个数字要具体化。 注意到用户特别标注“后台”索引存储,说明需要区别于表层原理的底层机制。考虑从四个维度展开: 1)物理存储层面:InnoDB的段/区/页结构(连16KB页内行记录格式都可以提) 2)数据结构层面:B+树节点如何映射到磁盘页 3)引擎差异:重点对比InnoDB和MyISAM索引存储的物理文件差异 4)动态维护:B+树分裂合并时页的分配机制 用户引用的资料2提到辅助索引回表机制,这个在回答里要图解化。可以用mermaid展示辅助索引→主键索引→数据行的三级跳过程,比文字描述直观。 需要警惕的是不能简单堆砌概念。比如解释“为什么非叶节点不存数据”时,要关联到磁盘预读原理:16KB页只存键值能容纳更多节点,把“减少IO次数”这个核心价值说透。 最后补充的注意事项里,关于页分裂的代价要具体。比如自增主键插入是顺序写,而UUID插入可能导致50%的页分裂率——这种量化表达比单纯说“性能更好”更有说服力。</think>### MySQL索引数据存储结构详解 #### 一、核心数据结构:B+树 MySQL索引采用**B+树结构**,这是专为磁盘存储设计的平衡多路搜索树: ```mermaid graph TD A[B+树节点] --> B[非叶节点] A --> C[叶节点] B --> D[存储索引键值+子节点指针] C --> E[存储数据] C --> F[双向链表连接] ``` 1. **节点设计** - **非叶节点**:仅存储索引键值+子节点指针(不存实际数据) - **叶节点**: - InnoDB:存储主键值+完整行数据(聚集索引) - MyISAM:存储行数据物理地址指针 - 所有叶节点通过双向链表连接 2. **磁盘优化设计** - 每个节点大小固定为**16KB**(`Innodb_page_size`) - 计算示例(主键为BIGINT): $$ \text{单节点子节点数} = \frac{16\text{KB}}{8\text{B(主键)} + 6\text{B(指针)}} \approx 1170 $$ $$ \text{三层树存储量} = 1170 \times 1170 \times 1170 \approx 1600\text{万行} $$ - 百万级数据仅需**3次磁盘IO**即可定位[^3] > 💡 **B+树 vs B树** > - B+树数据全在叶节点 → 查询路径长度稳定 > - B树非叶节点存数据 → 树高更高,随机IO更多 --- #### 二、存储引擎实现差异 ##### 1. InnoDB(聚集索引) ```mermaid graph LR A[主键索引] --> B[叶节点存储完整行数据] C[辅助索引] --> D[叶节点存储主键值] D -->|回表查询| A ``` - **数据文件**:`.ibd`文件(索引与数据一体) - **主键索引**:叶节点直接存储行数据(物理有序) - **辅助索引**:叶节点存储主键值,需**二次查找** - **优势**:主键查询极快(1次检索获数据) ##### 2. MyISAM(非聚集索引) ```mermaid graph LR A[索引] --> B[叶节点存储行地址] B --> C[.MYD数据文件] ``` - **文件分离**: - `.MYI`:索引文件(B+树结构) - `.MYD`:数据文件(堆表) - **所有索引**:叶节点存储数据行物理地址 - **特点**:主键/非主键索引结构相同 --- #### 三、关键存储细节 1. **页内结构(InnoDB)** ```plaintext | 页头 (38B) | 虚记录 | 记录堆 | 自由空间链表 | | 未分配空间 | 槽区 | 页尾 (8B) | ``` - **行记录存储**:按主键顺序物理存储(插入时可能页分裂) - **槽(Slot)机制**:页内记录通过二分查找定位 2. **辅助索引存储** - 叶节点存储:`索引列值 + 主键值` - 优势: - 数据更新时辅助索引无需修改 - 支持**覆盖索引**(避免回表) 3. **联合索引存储** - 索引键按声明顺序拼接 `(col1, col2) → 存储值 = col1值 + col2值` - **最左匹配原则**: `WHERE col1=1 AND col2=2` ✅ `WHERE col2=2` ❌(无法使用索引) --- #### 四、性能关键指标 | **场景** | **存储影响** | **优化建议** | |-----------------|-------------------------------|---------------------------| | **范围查询** | 叶节点双向链表 → $O(1)$跳转 | 优先使用自增整型主键 | | **插入性能** | 随机主键导致页分裂($O(\log n)$) | 避免UUID等随机主键 | | **空间占用** | 索引≈表数据20%-30%[^1] | 定期清理冗余索引 | | **更新代价** | 需更新所有相关索引 | 减少非必要索引 | > ⚠️ **页分裂代价** > 当叶节点满时(填充因子=15/16),触发页分裂: > - 新分配磁盘页 > - 迁移50%数据 > - 更新父节点指针 > 随机插入场景下可能产生**存储碎片** --- ```mermaid graph TD A[SQL查询] --> B{使用索引?} B -->|是| C[索引类型判断] C -->|主键索引| D[直接获取行数据] C -->|辅助索引| E[获取主键→回表查询] B -->|否| F[全表扫描] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值