面试题答案
一键面试B + 树索引底层原理
- 数据结构特点:
- 节点类型:B + 树由内部节点(非叶子节点)和叶子节点组成。内部节点仅存储索引键值,用于引导数据查询路径;叶子节点存储实际数据记录以及指向相邻叶子节点的指针,形成一个双向链表结构,方便范围查询。
- 节点分裂:当一个节点存储的键值达到其容量上限时,会进行节点分裂,将一半键值移到新节点,并在父节点中插入一个连接两个节点的键值。
- 高度平衡:B + 树通过节点分裂和合并等操作,保证树的高度平衡,使得从根节点到叶子节点的最长路径和最短路径长度之差不超过1,从而确保查询效率稳定。
- 查询过程:
- 从根节点开始,根据查询条件中的键值与节点中的键值进行比较,决定向下的搜索路径。
- 持续在内部节点中进行这种比较和路径选择,直到到达叶子节点。
- 在叶子节点中通过二分查找或顺序查找(如果没有排序)找到符合条件的数据记录。对于范围查询,利用叶子节点的双向链表结构,可以快速遍历获取范围内的数据。
高并发读写场景下基于B + 树特性的索引优化
- 前缀索引优化:
- 原理:对于较长的字符串类型字段,使用前缀索引,即仅对字段的前几个字符建立索引。因为B + 树索引存储键值会占用空间,较短的键值可以在一个节点中存储更多的索引项,减少树的高度,提升查询性能。
- 举例:假设一个表存储用户的邮箱地址,邮箱地址一般较长。如果对整个邮箱地址建立索引,会占用较多空间。可以对邮箱地址的前10个字符建立前缀索引。例如,原SQL查询为
SELECT * FROM users WHERE email = 'example@domain.com';
,优化后创建前缀索引CREATE INDEX idx_email ON users (email(10));
- 覆盖索引优化:
- 原理:使查询所需要的数据都能从索引中获取,而不需要回表操作。B + 树叶子节点存储了索引键值和指针,如果查询列都包含在索引中,就可以直接从索引中获取数据,减少磁盘I/O。
- 举例:假设有表
orders
,包含字段order_id
、customer_id
、order_amount
。查询SELECT order_id, order_amount FROM orders WHERE customer_id = 123;
,可以创建覆盖索引CREATE INDEX idx_customer_amount ON orders (customer_id, order_id, order_amount);
,这样查询时直接从索引获取数据,无需再到数据页获取。
- 索引顺序优化:
- 原理:根据高并发场景下的查询模式,调整索引列的顺序。在B + 树中,索引的顺序影响查询时的路径选择。如果查询经常以某些列作为条件,将这些列放在索引的前列,能更快定位数据。
- 举例:对于查询
SELECT * FROM products WHERE category = 'electronics' AND brand = 'Apple';
,创建索引CREATE INDEX idx_product ON products (category, brand);
,先根据category
定位,再根据brand
进一步筛选,比先按brand
后按category
的索引顺序更高效。
优化前后性能差异举例
- 前缀索引:
- 优化前:假设表
user_info
有字段user_name
(字符串类型,平均长度50),对user_name
全字段建立索引。查询SELECT * FROM user_info WHERE user_name = 'long_user_name_example';
,由于索引键值较长,节点存储的索引项少,树的高度可能较高,查询需要多次磁盘I/O,假设查询时间为100ms。 - 优化后:对
user_name
前10个字符建立前缀索引。同样的查询,由于索引键值变短,节点存储索引项增多,树的高度降低,查询时间可能缩短到30ms。
- 优化前:假设表
- 覆盖索引:
- 优化前:表
employee
有字段employee_id
、department
、salary
。查询SELECT employee_id, salary FROM employee WHERE department = 'HR';
,没有覆盖索引时,先通过索引找到department = 'HR'
的记录指针,再回表获取employee_id
和salary
,假设回表操作导致查询时间为80ms。 - 优化后:创建覆盖索引
CREATE INDEX idx_department_salary ON employee (department, employee_id, salary);
,查询直接从索引获取数据,查询时间可能减少到20ms。
- 优化前:表
- 索引顺序优化:
- 优化前:表
book
有字段author
、category
、title
。查询SELECT * FROM book WHERE category = 'fiction' AND author = 'John Doe';
,创建索引CREATE INDEX idx_author_category ON book (author, category);
,查询时先按author
筛选,可能需要遍历较多数据才能找到符合category
条件的记录,假设查询时间为120ms。 - 优化后:创建索引
CREATE INDEX idx_category_author ON book (category, author);
,先按category
筛选,能更快定位到符合条件的数据,查询时间可能缩短到40ms。
- 优化前:表