优先用create index,因其语句清晰、意图明确且不改动表结构;alter table适合需批量操作或同步修改表结构的场景,但可能触发重建并影响更大。

创建普通索引时,用 CREATE INDEX 还是 ALTER TABLE?
两者都能用,但行为和适用场景不同。CREATE INDEX 是纯索引操作,不改动表结构;ALTER TABLE 在加索引的同时可能触发表重建(尤其在 MyISAM 或旧版本 InnoDB 中),影响更大。
推荐优先用 CREATE INDEX,语句更清晰、意图更明确:
CREATE INDEX idx_user_email ON users(email);
如果需要在建索引时顺便加约束(比如唯一性),就必须用 ALTER TABLE:
ALTER TABLE users ADD INDEX idx_user_status (status);
- 索引名建议自定义,避免 MySQL 自动生成类似
idx_1的名字,后续删索引或查INFORMATION_SCHEMA时难定位 - 复合索引字段顺序很重要:查询条件中左边连续匹配才生效,
INDEX(a,b,c)能加速WHERE a=1 AND b=2,但对WHERE b=2无效 - 对大表加索引会锁表(尤其 MyISAM)或产生长事务(InnoDB 在 5.6+ 支持
ALGORITHM=INPLACE,但仍需评估负载)
删除普通索引必须知道的两个命令
删索引只有两种合法方式:DROP INDEX 和 ALTER TABLE ... DROP INDEX。没有 DELETE INDEX,也没有 REMOVE INDEX —— 写错就报错。
语法上,DROP INDEX 必须指定表名:
DROP INDEX idx_user_email ON users;
而 ALTER TABLE 方式更常见于运维脚本,因为统一用 ALTER TABLE 管理结构变更:
ALTER TABLE users DROP INDEX idx_user_email;
- 索引名大小写敏感(取决于系统变量
lower_case_table_names),执行前先查确认:SHOW INDEX FROM users; - 不要依赖「索引名和字段名一样」——
ADD INDEX email (email)创建的索引名就是email,但DROP INDEX email ON users删的是索引,不是字段 - MySQL 8.0+ 支持
INVISIBLE索引,删之前注意别误删了隐形索引(SHOW INDEX里Visible列为NO)
为什么 SHOW INDEX 查不到刚建的索引?
常见原因就三个:权限不足、表名写错、或者索引建在视图或临时表上(MySQL 不允许给视图建索引)。
最稳妥的验证方式是直接查 INFORMATION_SCHEMA.STATISTICS:
SELECT INDEX_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'users' ORDER BY SEQ_IN_INDEX;
-
SHOW INDEX FROM users只显示当前用户有SELECT权限的表索引,没权限就为空 - 建索引后立即查不到,也可能是事务未提交(极少见,仅在某些存储引擎或特殊隔离级别下)
- 如果用的是分区表,索引信息分散在各分区元数据中,
SHOW INDEX仍可查,但要注意Cardinality值可能不准
删索引后查询变慢?先看执行计划再动手
删索引本身很快,但后续查询性能掉坑里,往往是因为没验证实际 SQL 是否真用了那个索引。
用 EXPLAIN 对比删前后:
EXPLAIN SELECT * FROM users WHERE email = 'test@example.com';
- 重点看
type(是否为ref或range)、key(是否命中索引名)、rows(扫描行数是否激增) - 有些索引看似没被
WHERE用到,实则支撑了ORDER BY或GROUP BY,删了会导致文件排序(Using filesort) - 线上删索引前,最好在从库或影子库先跑一遍慢查询日志,确认没有业务 SQL 依赖它
索引不是越多越好,但删之前得知道它到底在撑什么。很多“冗余索引”其实正默默扛着某个凌晨定时任务的扫描压力。











