mysql 存储引擎和索引

黄光跃 / 2023-05-17 / 原文

存储引擎

引擎 特性 文件
InnoDB 默认,支持事务,支持外键,支持行锁和表锁 .frm 文件存储表结构
.ibd 文件存储数据和索引
MyISAM 不支持事务,不支持外键,只支持表锁不支持行锁
专门维护了一个常量保存每个表的总记录数(count 很快)
MyISAM 强调的是性能,所以性能上优于InnoDB,但安全性和并发性较低
.frm 文件存储表结构
.MYD 文件存储数据
.MYI 文件存储索引
Memory 数据存在内存中,所以性能上来看是最好的,缺点也很明显,一旦宕机数据就没了 只有表结构文件(只有 frm 文件)

索引

索引是一种数据结构,目的是提高检索数据的效率,减少磁盘I/O,也是一个文件存放在磁盘中(Memery 这种引擎数据都在内存中,索引也不可能有实质的文件了)
有利有弊,索引也是需要维护的,所以索引越多维护的成本也增大
按照不同的规则可以划分出不同的类型,比如按照字段个数:单列索引,复合索引;是否主键:主键索引,非主键索引。按照索引的数据结构上又能分为:聚簇索引和非聚簇索引

索引类型 支持的存储引擎 数据结构 节点内容 特点
聚簇索引/主键索引 InnoDB b+tree 叶子节点存放整行数据
非叶子存放主键和数据页的关系
一半不超过3级,因为3级都差不多上亿的数据量了
主键如果没有顺序,插入效率会很低,因为索引是有序的,所以没有序的数据可能要修改整棵索引树
非聚簇索引/辅助索引/二级索引 InnoDB b+tree 和聚簇索引的区别是:叶子节点只存放主键 可能会回表(符合索引下推就不回表)
MyISAM 索引 MyISAM b+tree 和聚簇索引的区别是:数据对应在硬盘的地址 一定会回表,因为索引和数据文件都不是同一个
可以没有主键,因为不支持聚簇索引
Hash 索引 Memory hash 数据结构类似 java 的 HashMap,根据 key 算下标,然后取数据,大多数情况下时间复杂度是 O(1),查询效率相当高
  • b-tree 是一种数据结构,这种数据结构是叶子节点和非叶子节点都可能存放数据。但是数据库索引没有采用这种结构!
  • 为什么非聚簇索引叶子不也放整行数据,这样就能避免回表?数据冗余,比如10个非聚簇索引,就要放11份数据
  • InnoDB 能不能使用 Hash 索引?不能手动创建 Hash 的索引,但是如果是访问频繁的数据,内部会自动构建一个自适应哈希索引
  • 既然 Hash 索引查询效率高,为什么 InnoDB 不使用 Hash 要用 B+Tree?
    • 根据 key 得到下标然后得到数据的,如果是 like 或者范围查询就 gg 了,因为 key 都不是常量
    • 默认查询的结果集是没有顺序的,如果要 ORDER BY 内部会再次对结果集进行排序计算
    • 如果是联合索引,hash 值是多个列联合计算的,无法根据其中的一个列进行索引

InnoDB 聚簇索引数据结构

  • 索引的数据结构是 b+tree,每个数据页(目录页)是双向链表,数据页里面的数据是单向链表,为什么是 b+tree 后面会说到
  • 计算机与磁盘交互的基本单位是数据页(图中目录页也是数据页,为了区分 bTree 的叶子节点和非叶子节点的叫法而已),每个数据页大小16k
  • sql 不管走不走索引都要发生磁盘交互,因为索引也是文件。数据会放在多个数据页,索引的目的是提高检索效率减少磁盘IO次数
  • 比如要找 id=9 的数据,查询过程如下:
    • 先到根节点的目录页,里面是个单向循环链表,能确定在目录页19
    • 目录页19 里面的节点也是单向循环链表,能知道数据位于数据页21
    • 到数据页21 里面得到 id=7 的数据

b+tree 和 b-tree

B+Tree 只是叶子节点才存放数据,B-Tree 非叶子节点也可能存放数据,因为数据页的大小是固定的 16k,所以 B-Tree 更高瘦
B+Tree 查询更稳定,正因为有的数据放在目录页,而一个页的大小又是固定的,所以快的时候效率高有的时候就比较低