理解 B+ 树索引、联合索引与常见慢 SQL 优化思路
索引是帮助 MySQL 高效获取数据的数据结构,类似书籍的目录。
B 树:数据分布在所有节点上,范围扫描不如 B+ 树高效。
哈希索引:只适合等值查询,不支持范围查询和排序。
如果一个查询所需的所有列都能在某个索引中直接获得,而不需要回表到聚簇索引,就称该索引为覆盖索引。
-- 联合索引 (user_id, status, created_at)
CREATE INDEX idx_user_status_created
ON order(user_id, status, created_at);
-- 查询只用到了索引中的列
SELECT user_id, status, created_at
FROM order
WHERE user_id = 1001 AND status = 'PAID';
上面的查询可以仅通过 idx_user_status_created 索引完成,无需回表,I/O 更少,性能更好。
对于联合索引 (a, b, c),索引可以被用到的前缀是:
但不能单独用 (b)、(c) 或 (b, c)。
WHERE LEFT(a, 3) = 'abc' 导致索引失效。WHERE DATE(create_time) = '2024-01-01'。LIKE '%abc'。WHERE age + 1 = 18。EXPLAIN SELECT * FROM user WHERE phone = '138...';
const、ref 越好,ALL 为全表扫描。Using filesort、Using temporary 等提示。表示 MySQL 需要额外的排序步骤(可能在内存或磁盘),而不是利用索引有序性。
user_id 无索引,还对 created_at 做了函数处理。(user_id, created_at) 建联合索引。DATE(created_at) = '2024-01-01' 改为范围查询 created_at >= '2024-01-01 00:00:00' AND created_at < '2024-01-02'。WHERE a = 1 AND b = 2 AND c = 3 -- ✅ 使用 (a,b,c)
WHERE a = 1 AND c = 3 -- ✅ 使用 (a)
WHERE b = 2 AND c = 3 -- ❌ 无法使用 (a,b,c)
WHERE a > 1 AND b = 2 -- ✅ a 范围,b 可能部分使用
WHERE a LIKE 'abc%' AND b = 2 -- ✅ 支持前缀匹配
WHERE a LIKE '%abc' AND b = 2 -- ❌ a 无法走索引
核心原则:从最左列开始连续匹配,中间一旦断开,后面的列无法利用索引有序性。
LIKE 'abc%',可以用到 B+ 树索引。LIKE '%abc' 这类前置通配符,必要时可考虑倒排索引或搜索引擎。