
理解 MySQL B+ 树索引:磁盘 IO、范围查询与性能优化
MySQL (InnoDB)主要使用 B+ 树索引,而不是哈希、二叉树或B树。
使用B+树的主要原因是B+树对磁盘IO友好,减少了磁盘IO操作,从而提高了查询的速度。 想象你在一本1000页的书中查找某个知识点,如果没有目录(索引),你只能一页一页的翻,这其实就是全书查找(对比到数据库就是全表扫描),这样的查找方式非常慢(效率低下)。但如果这本书有详细的目录那查找起来是不是快了很多?而B+树不仅是有目录,还是多层级目录(根目录只存大概分类、第2层目录存细化分类、。。。、最终数据-叶子节点),这样查询效率自然就高了。
B+树的非叶子节点只存储键值,不存储数据,叶子节点存数据;另外B+树是多叉树(相对二叉树),通常一个节点包含多个子节点,这就减少了树的高度。
举个栗子🌰:如果一个B+树索引有1000个分叉,那差不多只需要3层即可存储10亿条数据,这意味着查询时最多只需要3次磁盘IO。
注意:实际应用中索引键的类型和行数据的大小将直接影响数据的存储量
// InnoDB存储引擎每个节点(页)的大小通常为16KB // 每个索引项由索引键值和指向子节点的指针组成 // 假设键值以 bigint 类型为例,需占用 8 字节,指向子节点的指针占用固定的 6 字节 // 每个索引项的大小 = 8 + 6 = 14字节 每个节点可以存储的索引项数量 = 16KB / (8B + 6B) = 1170 个 // 三层 B+ 树的存储容量计算方法如下: 第一层(根节点):存储 1170 个指向第二层的指针; 第二层(中间节点):每个节点再存储 1170 个指针 = 1170 x 1170 = 1368900 个叶子节点; 第三层(叶子节点):存储实际的数据行指针。 假设每行数据大小为1KB,则每个叶子节点(16KB)可以存储16行数据,那么三层 B+ 树的 总存储容量 = 1368900(叶子节点数)x 16(每个叶子节点存储的数据行数)= 21902400 行, 也就是大约两千一百万行数据。 所以优化MySQL性能的一个可行方案就是控制索引键和要存储数据的大小,如下表,索引键占用的空间越大每个索引页能存储的索引项就越少,从而可能导致B+树的层级增加,以至查询性能下降(磁盘IO次数变多)。
数据类型 占用大小 是否适合索引? 备注 TINYINT 1字节 ✅ SMALLINT 2字节 ✅ INT 4字节 ✅ BIGINT 8字节 ✅ CHAR(10) 10字节 ⚠️ 定长字符串,存储开销比INT大 VARCHAR(255) 变长(最长767字节) ❌ 变长字符串会导致索引存储空间大,影响性能 TEXT/BLOB 不定长(存储在外部页) ❌ MySQL不能直接索引TEXT/BLOB类型 另外也可以通过启动MySQL时指定 –innodb-page-size=32K 或 通过my.cnf修改MySQL默认节点的大小的方式来降低树的高度: