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主键索引和二级索引的核心特性和操作方式,包括创建、查询、维护和优化等方面。