索引就是数据库的“目录页”,不建它,查得越慢,表越大越明显
MySQL 默认不给任何字段建索引——就像一本没目录的 1000 页书,你要找“事务隔离级别”这个词,只能一页页翻。建了索引,相当于提前把关键词按顺序整理好,再附上对应页码(即数据行位置),
SELECT时直接跳转,省掉全表扫描(
type: ALL)的 IO 开销。实际中,10 万行以上的表,一个没索引的
WHERE user_id = 12345可能要扫几万行;加了索引后,通常只需 3–4 次磁盘 IO 就定位到数据。
什么时候建索引?看查询条件和执行计划,不是看“字段重不重要”
建索引不是凭感觉,而是看
EXPLAIN输出里哪些列反复出现在
WHERE、
ORDER BY、
GROUP BY或
JOIN条件中。常见有效场景包括:
WHERE status = 'active'—— 但前提是该字段区分度高(比如 90% 是 active 就别建)
ORDER BY created_at DESC LIMIT 20—— 索引能避免排序临时表
JOIN orders ON users.id = orders.user_id—— 关联字段必须有索引,否则驱动表每扫一行,被驱动表都全表扫一遍 组合查询如
WHERE category = 'book' AND price BETWEEN 20 AND 50—— 考虑建联合索引
(category, price),注意最左前缀原则
为什么有时候建了索引也不走?这些操作一写就失效
索引不是建了就自动生效。MySQL 优化器会权衡成本,遇到以下情况,常直接放弃索引,退化为全表扫描:
对索引列用函数:WHERE YEAR(create_time) = 2025→ 改成
WHERE create_time >= '2025-01-01' AND create_time隐式类型转换:
user_id是
VARCHAR,却写
WHERE user_id = 12345→ MySQL 自动转成数字比较,索引失效 前导通配符:
WHERE name LIKE '%john'→ B+Tree 无法从左边开始匹配,
LIKE 'john%'才能用索引 OR 连接非索引字段:
WHERE a = 1 OR b = 2,若只有
a有索引,整个条件大概率不用索引 索引列参与计算:
WHERE score * 2 > 100→ 改成
WHERE score > 50
建索引不是免费的,写多读少的表要格外谨慎
每次
INSERT、
UPDATE、
DELETE都要同步更新所有相关索引树,尤其在高并发写入场景下,索引越多,写延迟越明显,甚至引发锁竞争。同时: 每个索引都占磁盘空间,
VARCHAR(255)字段建索引,可能比原数据还大 过多索引会让优化器选错执行计划,因为要花时间评估哪个索引“更优” 主键索引(聚簇索引)决定数据物理存储顺序,
INNODB表只能有一个;其他都是二级索引,查完还要回表取完整行
真正该建索引的地方,是那些被高频查询、且过滤性足够强的字段——不是所有
WHERE都值得加,更不是所有字段都适合单独建索引。联合索引的设计、字段顺序、是否覆盖查询,才是进阶关键。
