没有索引会怎样
查询 WHERE email = ? 时,没有索引就只能逐行扫描整张表。数据量大时这是性能灾难。索引相当于给列建了目录,让查找从 O(n) 降到 O(log n)。
B+ 树索引
主流关系库的索引是 B+ 树:有序、矮胖、叶子相连。等值查询走树定位,范围查询沿叶子链表顺序读,都很高效。
两个关键点
- 回表:二级索引只存索引列和主键,拿到主键后还要回主表取其他字段;覆盖索引(索引已含所需列)可避免回表;
- 最左前缀:联合索引
(a, b, c)只能从左用起,WHERE b = ?用不上该索引。
不是越多越好
- 拖慢写入:每次插入 / 更新都要维护索引;
- 占空间:索引也是数据;
- 选错列:低基数列(如性别)建索引收益极低。
索引设计与上线流程
索引改动的风险常被低估,建议按固定流程执行:
- 先看慢查询日志:以真实慢查询为依据建索引,而不是“感觉这个字段会被查”;
- 在接近生产的数据量上验证:小表上不加索引也很快,索引收益必须在大数据量上评估;
- 评估写入代价:每个索引都会拖慢写入,写多读少的表应严格控制索引数量;
- 大表在线加索引:MySQL 支持在线 DDL,但仍应避开高峰并关注锁与复制延迟;
- 上线后回归:确认目标查询的执行计划确实走了新索引,避免“加了索引没用上”的常见结局。
另外,删除不再使用的索引同样重要:长期积累的冗余索引会持续消耗写入性能与存储,建议每季度审视一次索引使用统计。
读多写少与写多读少的差异
- 写密集表的策略:日志、事件与流水类表写入频繁,索引数量应严格控制,只保留查询真正需要的少数几个,其余通过异步汇总或离线分析解决。
- 读密集表可以更宽容:以查询为主的表可以针对常见组合建立多个索引,但仍要定期清理长期未被使用的索引。
- 避免在写入高峰做结构变更:加索引与改字段应安排在低谷,并提前评估对复制延迟的影响,避免主库变更拖慢从库。
- 大表考虑分区:当单表数据量达到瓶颈时,按时间或业务维度分区能显著缩小扫描范围,并让归档变成一次分区操作而不是逐行删除。
- 关注缓存命中:索引有效不代表查询快,若索引与数据总大小超出内存,随机读会转为磁盘操作,此时应重新评估数据模型或冷热分离。
索引优化的目标不是让每条查询都走索引,而是在可接受的写入成本下,让关键查询的响应稳定在预期范围内。