WHERE条件列未建索引是查询慢的最常见原因;应使用EXPLAIN检查是否全表扫描,优先为单列或按等值在前/范围在后建立联合索引,并避免对索引列使用函数。

WHERE 条件列必须建索引
查询慢的最常见原因是 WHERE 子句里用了没索引的字段。MySQL 只能全表扫描,数据量一过十万行,响应就明显卡顿。
实操建议:
- 用
EXPLAIN SELECT ...看type是否为ALL(全表扫描),是就说明缺索引 - 单列查询优先建单列索引,比如
WHERE status = 'active'→ 给status建索引 - 多条件 AND 查询(如
WHERE user_id = 123 AND created_at > '2024-01-01'),考虑联合索引,顺序按「等值条件在前、范围条件在后」——(user_id, created_at)有效,反过来则created_at索引失效 - 避免对索引列做函数操作,比如
WHERE YEAR(created_at) = 2024会跳过索引;改写成WHERE created_at >= '2024-01-01' AND created_at
ORDER BY 和 GROUP BY 字段要进索引
即使 WHERE 已走索引,如果 ORDER BY 或 GROUP BY 的字段不在该索引中,MySQL 仍可能触发 Using filesort 或 Using temporary,性能陡降。
实操建议:
-
EXPLAIN结果里出现Using filesort,说明排序没走索引;出现Using temporary,大概率是GROUP BY或去重没利用索引 - 把
ORDER BY字段追加到 WHERE 索引末尾,例如查询WHERE category = 'book' ORDER BY price DESC,索引应建为(category, price) - 注意方向一致性:联合索引中所有字段都升序时,
ORDER BY a ASC, b ASC能命中;但ORDER BY a ASC, b DESC在 MySQL 8.0 之前无法使用索引排序(8.0+ 支持混合方向)
避免冗余索引和过宽索引
索引不是越多越好。重复或过长的索引会拖慢写入(INSERT/UPDATE/DELETE),还浪费内存和磁盘空间。
实操建议:
- 已有索引
(a, b)时,再建(a)就是冗余——前者已能支撑单查a - 不要给长文本字段(如
TEXT、超长VARCHAR)直接建全文索引以外的索引;必须用时加前缀,如INDEX idx_name (name(191)) - 联合索引字段数建议 ≤ 3 个;超过后维护成本高,且选择性常不理想
- 用
SELECT COUNT(DISTINCT col)/COUNT(*)估算选择性,低于 0.01 的字段(如gender)通常不适合作为索引首字段
区分主键、唯一索引与普通索引的用途
主键不只是“保证唯一”,它决定了聚簇索引的物理存储顺序;普通索引叶子节点存的是主键值,不是数据行本身。
实操建议:
- 尽量用自增
INT或BIGINT当主键;避免用 UUID 或字符串作主键,会导致插入随机、页分裂频繁、B+ 树深度增加 - 业务上需唯一约束的字段(如
email),用UNIQUE INDEX,不是普通索引——既防重又可用于查询加速 - 覆盖索引能避免回表:如果
SELECT a, b FROM t WHERE c = 1,建索引(c, a, b)后,MySQL 直接从索引取全部字段,不用再查聚簇索引 - 注意
NULL:普通索引允许NULL值重复;唯一索引允许多个NULL(MySQL 行为),这点容易被忽略导致去重逻辑出错
SELECT *。上线前务必用生产级数据量压测,否则索引可能只在测试环境“看起来很美”。










