最近正在复习Java八股,所以会将一些热门的八股问题,结合ai与自身理解写成博客便于记忆
一、索引基础原理
1. 索引的本质
索引是存储在磁盘上的数据结构,用于快速定位数据,相当于书籍的目录。MySQL索引采用B+树作为主要数据结构。
2. B+树核心特性
多路平衡查找树:保持数据有序且查询效率稳定
叶子节点链表连接:支持高效范围查询
非叶子节点只存键值:减少树高度,提高IO效率
所有数据存于叶子节点:查询路径长度一致
-- 创建索引语法
CREATE INDEX idx_name ON table_name(column1, column2);
二、索引类型详解
1. 按数据结构分类
索引类型 | 实现方式 | 特点 | 适用场景 |
B+Tree索引 | B+树 | 支持范围查询 | 默认索引类型,适合大部分场景 |
Hash索引 | 哈希表 | 精确查询O(1),不支持排序 | 等值查询,内存表 |
Full-text索引 | 倒排索引 | 文本搜索 | 文本内容搜索 |
R-Tree索引 | 空间索引 | 地理数据存储 | GIS地理信息系统 |
2. 按逻辑分类
主键索引(PRIMARY KEY):唯一且非空,InnoDB的聚簇索引
唯一索引(UNIQUE KEY):保证列值唯一性
普通索引(INDEX):加速查询,允许重复值
组合索引(复合索引):多列组成的索引
三、索引比较
对比维度 | 聚簇索引 | 非聚簇索引 |
数据存储方式 | 索引与数据存放在一起(索引即数据) | 索引与数据分离(需回表查询) |
主键要求 | 必须有主键 | 无特殊要求 |
索引数量 | 每个表只有一个 | 每个表可有多个 |
查询性能 | 主键查询极快 | 需要二次查找 |
四、索引优化策略
1. 索引失效场景
使用`!=`、`<>`、`NOT IN`操作符
对索引列使用函数或运算:`WHERE YEAR(create_time) = 2023`
隐式类型转换:`WHERE user_id = '123'`(user_id是int类型)
前导模糊查询:`WHERE name LIKE '%张'`
违反最左前缀原则(组合索引)
2. 高性能索引原则
1. 选择区分度高的列:`COUNT(DISTINCT col)/COUNT(*)`越高越好
2. 短索引原则:使用前缀索引`ALTER TABLE t ADD INDEX idx(column(10))`
3. 覆盖索引优化:查询列都包含在索引中
4. 索引列不参与计算:`WHERE id + 1 = 5` → `WHERE id = 4`
五、面试高频问题解析
1:为什么MySQL默认使用B+树而不是B树?
参考答案:
1. IO效率更高:B+树非叶子节点不存数据,单次IO可加载更多键值
2. 查询更稳定:所有查询都要走到叶子节点,时间复杂度稳定O(log n)
3. 范围查询优势:叶子节点形成链表,范围查询无需回溯
4. 更适合磁盘存储:B+树的扇出系数更高,树高更低
2:什么是回表查询?如何避免?
问题解析:
回表:通过非聚簇索引找到主键后,再通过主键查询完整记录的过程
优化方案:
-- 使用覆盖索引(索引包含所有查询字段)
SELECT id, name FROM users WHERE name = '张三';
-- 创建组合索引
CREATE INDEX idx_name_age ON users(name, age);
3:百万级数据如何创建索引?
解决方案:
1. 低峰期执行:`ALTER TABLE ADD INDEX idx_name ON large_table(column)`
2. 分批处理:先创建无索引临时表,导入数据后添加索引
3. 使用在线DDL(MySQL 5.6+):
ALTER TABLE large_table ADD INDEX idx_name (column), ALGORITHM=INPLACE, LOCK=NONE;
4:如何查看索引使用情况?
-- 查看索引使用
EXPLAIN SELECT * FROM users WHERE name = '张三';
-- 查看索引统计信息
SHOW INDEX FROM users;
-- 开启索引监控
SET GLOBAL userstat=1;
SELECT * FROM INFORMATION_SCHEMA.INDEX_STATISTICS;
六、总结与最佳实践
1. 设计原则:
每张表建议不超过5个索引
组合索引字段数不超过5个
字符串索引使用前缀索引
2. 避坑指南:
避免过度索引(写性能下降)
不使用外键(应用层保证)
定期清理无用索引
3. 性能铁律:
索引优化效果:覆盖索引 > 组合索引 > 单列索引
查询速度:主键查询 > 唯一索引 > 普通索引 > 全表扫描