create index与alter table add index效果一致,均生成b+tree结构,区别仅在于语法场景:前者聚焦索引本身,适合dba维护;后者作为表结构变更一部分,适合开发迁移脚本。

CREATE INDEX 和 ALTER TABLE ... ADD INDEX 是创建普通索引最常用的两种方式,但选错时机、字段或顺序,反而会让查询变慢甚至失效。
普通索引该用 CREATE INDEX 还是 ALTER TABLE?
两者效果完全一致,底层都生成相同的 B+Tree 结构,区别只在语法习惯和上下文:
-
CREATE INDEX idx_user_email ON users (email);更聚焦索引本身,适合 DBA 或批量脚本维护 -
ALTER TABLE users ADD INDEX idx_user_email (email);把索引当作表结构变更的一部分,适合开发在迁移脚本中统一管理(比如和ADD COLUMN放在一起) - 二者都不能用于添加主键或外键约束——主键必须用
PRIMARY KEY,外键必须用FOREIGN KEY
WHERE 条件里用了字段,就一定能走普通索引吗?
不能。常见失效场景比想象中多,且错误往往藏在 SQL 写法里:
-
WHERE email = 'a@b.com'✅ 走索引;WHERE UPPER(email) = 'A@B.COM'❌ 函数导致索引失效 -
WHERE name LIKE 'zhang%'✅ 前缀匹配可用索引;WHERE name LIKE '%zhang'❌ 无法使用 B+Tree 的有序性 -
WHERE status = 1 AND category_id = 5—— 若只有category_id单列索引,status区分度极低(比如只有 0/1),优化器大概率放弃索引,直接全表扫描 - 隐式类型转换:
WHERE user_id = '123'(user_id是INT)会触发转换,可能跳过索引
组合索引字段顺序为什么不能随便调?
MySQL 遵循“最左前缀原则”,顺序直接决定哪些查询能命中:
- 建了
INDEX idx_name_age (name, age),以下查询能用上索引:WHERE name = 'Alice'、WHERE name = 'Alice' AND age > 25、WHERE name = 'Alice' AND age = 30 - 但
WHERE age = 25或WHERE age = 25 AND name = 'Alice'(注意条件顺序颠倒)—— 第二种能用(优化器会重排),第一种完全无法利用该索引 - 如果业务中
age单独过滤频次高,又必须和name组合查,那就得另建一个以age开头的索引,比如idx_age_name
普通索引对写操作的影响容易被低估
每多一个普通索引,INSERT / UPDATE / DELETE 就得多维护一份 B+Tree 结构:
- 插入一条记录,要同时写入主键索引 + 所有普通索引的叶子节点,还涉及页分裂、缓冲池刷盘等开销
- 高频更新的字段(如
last_login_time)上建普通索引,写放大效应明显,QPS 上去后容易成为瓶颈 - 索引不是越多越好——
SHOW INDEX FROM table_name查出的Cardinality值接近 0 或远低于总行数,说明该索引基本没被用到,该删
EXPLAIN 看 key 和 rows 字段。











