InnoDB是mysql的默认引擎,索引原理是B+树。
InnoDB的索引方式
首先,数据库的目录也是很庞大的,不能放在内存里。
而磁盘的读写速度是比内存慢几个数量级。
而且顺序读一块比随机I/O划算,也就是局部性原理。
所以:InnoDB把数据和目录都放在默认大小16KB的数据页中。每次读都读一个页。
每个数据页是怎么组织呢?
每个页除了首部和底部的其他额外信息。其他的都是行记录。
每条行记录的格式为:next_record|其他信息|实际行信息。
所以就是以单向链表的形式组织着行记录。按主键排序。
(所以用自增主键更好维护,加到列表最后就可以)
为了折中 高效查询 和 增删记录的维护的低成本。
InnoDB把 4~8 条记录作为一组,每组的最大主键的记录作为组长,保存小组的记录数量来维护个数(分裂合并)
把所有组长的主键和位置有序保存到一个数组中。称为槽。
所以根据槽可以二分快速查到小组,再遍历到具体记录。
这样查询高效,也不用每次都维护槽数组,只有小组数量太大太小分裂合并时重新维护数组。
页间的组织方式
每个数据页中还要两条伪记录,是记录链表的头和尾,分别保存着主键的 最小值 和 最大值。
所有叶子节点(数据页)都是这么保存记录的,所以需要目录来快速的找到页。
目录也是很大的,也是同样用行记录组织在数据页中。
为了目录页的存的行数据更多,行数据只用保存主键和数据页的索引,这样树的高度更小,这也是B+树和B树的区别。
一般的B+树不超过4层。
一个目录页大约1000条记录(8字节(主键)+6字节(页指针)= 14字节),三层目录,有大约10^9条目录记录,所以可以有这么多叶子节点(数据页16KB)。所以是16TB的容量。
(64TB 的数据容量是 InnoDB 通过使用溢出页和灵活的存储机制来实现的,特别是处理 BLOB
和 TEXT
类型的大字段时,它们会占用额外的磁盘空间,从而使总数据容量扩展到 64TB。)
总结InnoDB的主索引
B+树更像是一种逻辑上树,每块目录页读后可以快速的解析。
主要是不超过4层的高度,让引擎只用在磁盘读不超过4次,而且可以范围查询。
主索引这样的也就是聚簇索引(记录和索引在一起)。
二级索引
根据上面的主索引的方法,我们可以看到,如果要按其他列查询只能遍历所有数据查询。
所有我们可以更加其他列建立新的辅助索引(或者几列,叫做联合索引)。
用 二级索引列 ,排序,建立新的B+树,记录只用保存对应主键。
根据 二级索引列 查询到 主键 ,再用主键到主索引里查询记录,这叫回表。
回表查询是随机I/O,(局部性原理没啥用了)
所以能不回表尽量不回表。
必须回表就减少回表次数。
优化
主要就是减少回表:
-
索引覆盖:在二级查询的时候,前缀查询是有效的,联合索引可以查到可能需要的值,就不用回表了。
-
索引下推:在二级索引中使用,当条件不完全依赖于索引时,它会尽量在索引扫描的过程中对其他列进行过滤(比如查询
SELECT * FROM employees WHERE age = 30 AND name LIKE 'J%';
),减少回表操作。