2.3.1. 索引数据结构
索引就是能够提高查询速度的一种数据结构,在数据插入时就进行了排序(会影响插入和更新的性能),索引广泛使用的是B+树索引。
B+树索引结构:
目前是基于磁盘排序效率最高的数据结构,树非常矮通常3~4层所以访问效率高,查询一条数据只用三到四次I/O,可以存放千万到亿的排序数据。
B+ 树索引由根节点(root node)、中间节点(non leaf node)、叶子节点(leaf node)组成,叶子节点存放所有排序后的数据。B+树高度为1,就只有一个页既是根节点也是叶子节点。随着插入 B+ 树索引的记录变多,1个页(16K)无法存放这么多数据,会发生 B+ 树的分裂,B+ 树的高度变为 2,当 B+ 树的高度大于等于 2 时,根节点和中间节点存放的是索引键对,由(索引键、指针)组成。
索引键就是排序的列,而指针是指向下一层的地址,在 MySQL 的 InnoDB 存储引擎中占用 6 个字节。下图显示了 B+ 树高度为 2 时,B+ 树索引的样子:
若要查询索引键值为 5 的记录,先查找根节点,查到键值对(20,地址),表示小于 20 的记录在地址指向的下一层叶子节点中。根据下一层地址就可以找到最左边的叶子节点,在叶子节点中根据二叉查找就能找到索引键值为 5 的记录。
优化B+树索引的插入性能:
B+ 树在插入时就对要对数据进行排序,但排序的开销并没有那么大,排序是 CPU 操作(当前一个时钟周期 CPU 能处理上亿指令)。
真正的开销在于 B+ 树索引的维护,保证数据排序,这里存在两种不同数据类型的插入情况。
- 数据顺序(或逆序)插入: B+ 树索引的维护代价非常小,叶子节点都是从左往右进行插入,比较典型的是自增 ID 的插入、时间的插入(在自增 ID 上,时间等具有顺序的列上创建索引,则 B+ 树插入通常是比较快的)。
- 数据无序插入: B+ 树为了维护排序,需要对页进行分裂、旋转等开销较大的操作,另外,即便对于固态硬盘,随机写的性能也不如顺序写,所以磁盘性能也会收到较大影响。比较典型的是用户昵称,每个用户注册时,昵称是随意取的,在昵称上创建索引,插入是无序的,索引维护需要的开销会比较大。
对于 B+ 树索引,在 MySQL 数据库设计中,仅要求主键的索引设计为顺序,比如使用自增,或使用函数 UUID_TO_BIN 排序的 UUID,而不用无序值做主键。
UUID 由于是无序值,在插入时性能比起顺序值自增 ID 和排序 UUID,性能上差距比较明显。
在表结构设计时,主键的设计一定要尽可能地使用顺序值,这样才能保证在海量并发业务场景下的性能。
MySQL 单表的索引没有个数限制,根据业务查询的具体需求创建即可,不要迷信个数限制;
在真正业务上可能会创建一些低效的索引,优化器根本不会使用这些无效索引占用了空间,又影响了插入的性能,真正避免的是这种情况。