F
Member
在 MySQL InnoDB 中,索引基于 B+ 树实现。理解它的结构,就能理解大部分“索引失效”的原因。
一、聚簇索引与二级索引。 InnoDB 的主键索引是聚簇索引,叶子节点存放整行数据;二级索引的叶子节点存放索引列和主键值。通过二级索引查到主键后,再回主键索引取整行,这一步叫“回表”。如果查询所需的列全部包含在二级索引里,就能避免回表,即“覆盖索引”。
二、最左前缀原则。 联合索引 (a, b, c) 按 a、b、c 的顺序排序。查询条件只有 b 或 c 时,无法利用这个有序性;对 a 使用范围查询后,b 之后的列一般也无法用于定位(索引下推可在一定程度上缓解)。
三、常见失效场景。
1. 对索引列做函数或运算,例如 WHERE DATE(created_at) = ...
2. 隐式类型转换,例如字符串列与数字比较。
3. 以通配符开头的 LIKE '%abc'。
4. 区分度低的列,优化器判断全表扫描更便宜。
5. OR 条件中有一侧没有索引。
四、排查方法。 用 EXPLAIN 查看 type、key、rows、Extra 等字段;开启慢查询日志定位问题 SQL;必要时用 optimizer_trace 看优化器为什么放弃某个索引。
讨论问题:
1. 联合索引的列顺序,你们一般按什么原则确定?
2. 深分页(LIMIT 大偏移量)有哪些可靠的优化方式?
3. 在 PostgreSQL 等其他数据库中,类似问题的表现和处理有何不同?
一、聚簇索引与二级索引。 InnoDB 的主键索引是聚簇索引,叶子节点存放整行数据;二级索引的叶子节点存放索引列和主键值。通过二级索引查到主键后,再回主键索引取整行,这一步叫“回表”。如果查询所需的列全部包含在二级索引里,就能避免回表,即“覆盖索引”。
二、最左前缀原则。 联合索引 (a, b, c) 按 a、b、c 的顺序排序。查询条件只有 b 或 c 时,无法利用这个有序性;对 a 使用范围查询后,b 之后的列一般也无法用于定位(索引下推可在一定程度上缓解)。
三、常见失效场景。
1. 对索引列做函数或运算,例如 WHERE DATE(created_at) = ...
2. 隐式类型转换,例如字符串列与数字比较。
3. 以通配符开头的 LIKE '%abc'。
4. 区分度低的列,优化器判断全表扫描更便宜。
5. OR 条件中有一侧没有索引。
四、排查方法。 用 EXPLAIN 查看 type、key、rows、Extra 等字段;开启慢查询日志定位问题 SQL;必要时用 optimizer_trace 看优化器为什么放弃某个索引。
讨论问题:
1. 联合索引的列顺序,你们一般按什么原则确定?
2. 深分页(LIMIT 大偏移量)有哪些可靠的优化方式?
3. 在 PostgreSQL 等其他数据库中,类似问题的表现和处理有何不同?