InnoDB主键索引树和二级索引树

InnoDB主键索引树的结构

InnoDB存储引擎采用B+树作为主键索引的数据结构。主键索引的叶子节点存储完整的数据记录(即聚簇索引),而非叶子节点存储键值和指向子节点的指针。主键索引的B+树高度通常维持在3-4层,能有效支持千万级数据的高效查询。

-- 创建带有主键的表
CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(100),
    age INT,
    email VARCHAR(100)
) ENGINE=InnoDB;

主键索引树的查找过程通过二分法快速定位数据。例如查询id=5的记录,从根节点开始比较键值,沿着指针逐层向下查找,直到定位到具体的叶子节点。

二级索引树的结构

二级索引(非聚簇索引)同样使用B+树结构,但其叶子节点存储的是主键值而非完整数据记录。查询时需要先通过二级索引找到主键,再回表查询主键索引获取完整数据。

-- 创建二级索引
CREATE INDEX idx_name ON users(name);

二级索引树的叶子节点按索引列排序,但存储的是主键值。例如name索引的叶子节点可能存储("Alice",1),("Bob",2)这样的键值对。当通过name查询时,先找到对应主键,再回表查询。

主键索引与二级索引的查询差异

主键索引查询可以直接获取完整数据:

-- 主键查询(不需要回表)
SELECT * FROM users WHERE id = 5;

二级索引查询需要回表操作:

-- 二级索引查询(需要回表)
SELECT * FROM users WHERE name = 'Alice';

性能差异体现在回表操作上。覆盖索引可以避免回表:

-- 覆盖索引查询(不需要回表)
SELECT id, name FROM users WHERE name = 'Alice';

索引维护操作

插入数据时,需要同时更新主键索引和所有二级索引:

-- 插入数据会更新所有索引
INSERT INTO users VALUES (10, 'Charlie', 25, 'charlie@example.com');

删除操作同样需要维护所有索引:

-- 删除数据会更新所有索引
DELETE FROM users WHERE id = 10;

更新操作如果涉及索引列,也需要更新相应索引:

-- 更新name会更新二级索引
UPDATE users SET name = 'David' WHERE id = 5;

复合索引的结构

复合索引也是B+树结构,键值按索引定义的列顺序组合:

-- 创建复合索引
CREATE INDEX idx_age_name ON users(age, name);

复合索引的叶子节点存储(age,name)组合和主键值。查询时可以充分利用最左前缀原则:

-- 能使用复合索引
SELECT * FROM users WHERE age = 25 AND name = 'Alice';

-- 也能使用复合索引(最左前缀)
SELECT * FROM users WHERE age = 25;

索引选择与优化

EXPLAIN命令可以分析查询使用的索引:

EXPLAIN SELECT * FROM users WHERE name = 'Alice';

强制使用特定索引:

SELECT * FROM users FORCE INDEX(idx_name) WHERE name = 'Alice';

索引选择性是优化的重要指标:

-- 计算索引选择性
SELECT COUNT(DISTINCT name)/COUNT(*) FROM users;

索引的物理存储

InnoDB索引存储在表空间文件中。可以通过INNODB_SYS_INDEXES视图查看索引元数据:

SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES 
WHERE TABLE_ID = (SELECT TABLE_ID FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES 
WHERE NAME = 'test/users');

索引页的大小默认为16KB,可以通过参数调整:

[mysqld]
innodb_page_size=16K

索引分裂与合并

B+树在插入数据时会动态调整,发生页分裂:

-- 大量插入可能导致页分裂
INSERT INTO users SELECT * FROM large_users_table;

合并操作发生在删除大量数据后:

-- 删除大量数据后可能触发页合并
DELETE FROM users WHERE age > 60;

可以通过INNODB_METRICS监控索引分裂:

SELECT * FROM INFORMATION_SCHEMA.INNODB_METRICS 
WHERE NAME LIKE '%index_page%split%';

以上代码示例展示了InnoDB主键索引和二级索引的核心特性和操作方式,包括创建、查询、维护和优化等方面。

### InnoDB 存储引擎中 B+ 二级索引工作机制 #### 1. B+ 结构概述 B+ 是一种平衡数据结构,广泛用于数据库管理系统中的索引实现。在 MySQLInnoDB 存储引擎里,B+ 被用来构建高效的索引体系。与普通的 B 不同,在 B+ 中只有叶子节点存储真实的数据记录,而非叶节点仅保存键值用于引导查找路径[^3]。 #### 2. 二级索引定义 对于 InnoDB 表而言,默认情况下会创建一个主键作为聚簇索引(clustered index),而其他任何额外建立的索引则被称为二级索引(secondary indexes) 或者辅助索引(auxiliary indexes)[^5]。当用户基于某个字段创建了二级索引之后,该字段上的查询操作就可以利用这个索引来加速访问速度。 #### 3. 工作流程解析 假设存在一张 `users` 表,并且已经针对 `email` 列建立了名为 `idx_email` 的二级索引: - 当执行如下 SQL 查询语句时: ```sql SELECT * FROM users WHERE email='[email protected]'; ``` - 首先会在内存缓存池(Buffer Pool) 中尝试定位到对应的页(Page), 如果命中,则直接读取;如果没有找到对应页面,则需要从磁盘加载相应部分进入缓冲区; - 接着按照 idx_email 这棵 B+ 自顶向下逐层比较目标邮箱字符串与其他节点内的关键字大小关系直到抵达最底层即叶子结点位置; - 叶子结点除了包含 email 键外还会携带指向实际行记录物理地址的信息(通常是主键ID),因此下一步就是依据此信息再次回表扫描获取完整的列值集合返回给客户端应用。 这种设计使得即使是在大规模数据集上也能保持较高的检索效率,因为每次只需要遍历一棵相对较小的高度固定的形结构即可完成精准匹配过程[^4]。 ```python def search_secondary_index(index_tree, key_value): current_node = index_tree.root while not is_leaf(current_node): # 不断深入直至到达叶子节点 child_pointer = find_child_pointer(current_node, key_value) current_node = follow(child_pointer) row_id = locate_row_in_leaf(current_node, key_value) return fetch_full_record(row_id) def is_leaf(node): """判断当前节点是否为叶子节点""" pass def find_child_pointer(node, value): """寻找合适的子节点指针""" pass def follow(pointer): """跟随指针移动至下一个节点""" pass def locate_row_in_leaf(leaf, target_key): """在叶子节点内定位具体的行号""" pass def fetch_full_record(record_identifier): """根据行标识符抓取整条记录""" pass ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值