
MySQL索引底层原理剖析
B+树索引是MySQL最核心的存储结构,理解它的工作原理才能真正用好索引。InnoDB引擎默认使用B+树,这种数据结构能让查询时间复杂度稳定在O(log n)。所有数据都存储在叶子节点,非叶子节点只存键值和指针,一个页节点能存放500-1000条记录。
索引的物理存储是以页为单位的,默认16KB大小。当执行查询时,MySQL会先加载索引页到内存,通过二分查找快速定位数据。复合索引的存储方式特别有意思,它会把多个字段值拼接成索引键,这就是为什么会有最左前缀原则。
索引设计的黄金法则
索引类型 | 适用场景 | 存储大小 |
---|---|---|
主键索引 | 唯一标识记录 | 8字节 |
普通索引 | 加速查询 | 4-8字节 |
联合索引 | 多条件查询 | 各列大小之和 |
实战中的索引优化案例
电商平台的商品搜索是个典型场景。假设有商品表包含id、名称、分类、价格等字段,常见的查询是”手机”类目下价格在2000-5000元的商品。这时候应该建立(category_id, price)的联合索引,而不是单独建立两个单列索引。
分页查询优化也很关键。当处理limit 10000,10这种深分页时,可以先通过索引查出主键,再用主键关联获取完整数据,避免大量回表操作。大表添加索引要特别注意,最好在业务低峰期进行,5亿条记录的表添加索引可能需要30-60分钟。
索引监控与维护技巧
MySQL提供了多种工具来监控索引使用情况。performance_schema可以统计索引的使用频率,发现那些从不被使用的”僵尸索引”。定期使用ANALYZE TABLE更新统计信息也很重要,优化器会根据这些数据决定是否使用索引。
对于字符串字段,合理使用前缀索引能显著减少索引大小。比如对varchar(255)的email字段,可以只索引前20个字符。但要确保选择性足够,一般 前缀长度能覆盖80-90%的数据区分度。
判断索引是否该删除,最直接的方法就是看它到底有没有被实际使用。performance_schema库里的table_io_waits_summary_by_index_usage表会记录每个索引的使用情况,重点关注COUNT_STAR这个字段。如果某个索引连续30天都没被访问过,那它基本上就是个摆设了。不过要注意,有些索引可能是为特定报表或季度性业务准备的,删除前最好确认下业务场景。
除了使用频率,索引的体积也是个重要考量因素。一个占用5-8GB的冗余索引不仅浪费存储空间,更会影响写入性能。每次INSERT或UPDATE操作时,MySQL都要维护这些”僵尸索引”,导致TPS下降20-30%都很常见。可以用SHOW INDEX FROM命令查看索引的Cardinality和Index_length,优先删除那些体积大但区分度低的索引。
常见问题解答
为什么我的索引没有被使用?
最常见的原因是查询条件不符合最左前缀原则,或者发生了索引失效操作。检查EXPLAIN结果中的possible_keys和key字段,确认是否使用了预期索引。 当优化器判断全表扫描更快时(比如查询覆盖了大部分数据),也会放弃使用索引。
联合索引中字段顺序应该如何设计?
应该把区分度高(选择性80-95%)的字段放在前面,等值查询字段优先于范围查询字段。例如用户表有gender和register_time字段,应该把register_time放在前面,因为时间字段的选择性通常高于性别字段。
大表添加索引需要注意什么?
数据量超过500万行的表, 在业务低峰期操作。InnoDB创建索引时会锁表,可能导致服务不可用。对于1亿条记录以上的表,可以考虑使用pt-online-schema-change工具在线修改表结构。
如何判断一个索引是否应该删除?
通过performance_schema.table_io_waits_summary_by_index_usage表查看索引使用频率,连续30天未被使用的索引可以考虑删除。同时检查索引大小,过大的冗余索引会影响写入性能。
字符串字段适合建索引吗?
varchar类型的字段可以建立索引,但 使用前缀索引优化。比如对email字段,可以指定索引前20个字符。需要注意前缀长度要能保证80-90%的选择性,避免因截断导致大量重复值。