mysql建索引不报错需注意:指定索引名与表名、text/blob字段须带前缀长度(如email(191))、联合索引遵循最左前缀原则、避免低区分度字段单独建索引。

CREATE INDEX 语句怎么写才不会报错
MySQL 创建索引最常出错的地方是忽略存储引擎限制和字段类型兼容性。InnoDB 支持前缀索引,但 MyISAM 对前缀长度限制更松;而全文索引(FULLTEXT)只支持 CHAR、VARCHAR 和 TEXT 类型,且仅在 MyISAM 或 InnoDB(5.6+)中可用。
基础语法必须带索引名和表名,字段列表用括号包裹:
CREATE INDEX idx_user_email ON users (email);
- 如果字段是
TEXT或BLOB,必须指定前缀长度,例如(email(191)),否则报错ERROR 1170 (42000): BLOB/TEXT column 'email' used in key specification without a key length - 联合索引字段顺序不能随意调换——
(status, created_at)无法加速只查created_at的查询 - 避免对低区分度字段(如
gender、is_deleted)单独建索引,优化器大概率会忽略它
ALTER TABLE ADD INDEX 和 CREATE INDEX 有什么区别
两者最终效果一致,但执行路径不同:ALTER TABLE 是 DDL 操作,在 MySQL 5.6+ 默认使用 ALGORITHM=INPLACE(不锁表),而 CREATE INDEX 在某些旧版本或特定配置下可能触发表拷贝。
更关键的是语义清晰度:如果你正在改表结构,用 ALTER TABLE ... ADD INDEX 更自然;如果是纯加索引,CREATE INDEX 更直白。示例:
ALTER TABLE orders ADD INDEX idx_order_status_time (status, order_time);
- 加唯一索引必须用
ADD UNIQUE INDEX或CREATE UNIQUE INDEX,不能省略UNIQUE - 如果表有大量数据,建议在业务低峰期执行,并确认
innodb_online_alter_log_max_size足够,否则可能因日志溢出失败 -
CREATE INDEX不支持IF NOT EXISTS(MySQL 8.0.19+ 才支持),而ALTER TABLE ... ADD INDEX也不支持该子句,真要防重需先查information_schema.STATISTICS
什么时候该用前缀索引?怎么选长度
前缀索引适用于长文本字段(如 url、title),目的是节省索引空间并加快查找,但会损失精确匹配能力。选长度不是拍脑袋——得看实际数据的区分度。
由于疫情等原因大家都开始习惯了通过互联网上租车服务的信息多方面,且获取方式简便,不管是婚庆用车、旅游租车、还是短租等租车业务。越来越多租车企业都开始主动把租车业务推向给潜在需求客户,所以如何设计一个租车网站,以便在同行中脱颖而出就重要了,易优cms针对租车行业市场需求、目标客户、盈利模式等,进行策划、设计、制作,建设一个符合用户与搜索引擎需求的租车网站源码。 网站首页
先用以下查询估算不同前缀长度的重复率:
SELECT COUNT(*) AS total, COUNT(DISTINCT LEFT(url, 10)) AS prefix_10, COUNT(DISTINCT LEFT(url, 20)) AS prefix_20 FROM pages;
- 目标是让
COUNT(DISTINCT LEFT(...)) / COUNT(*)接近 0.95 以上,比如prefix_20达到 0.97 就没必要再加到 30 - InnoDB 中,前缀长度单位是字符数,不是字节数;UTF8MB4 下一个中文占 4 字节,但索引长度计算仍按字符计
- 前缀索引无法用于
ORDER BY或GROUP BY(除非整个表达式都用前缀),也影响LIKE 'abc%'的走索引行为
建完索引为什么查询还是没变快
索引建了不等于被用上。最常见原因是查询条件没命中索引最左前缀,或者优化器认为全表扫描更快(比如返回行数超过约 20% 总量)。
用 EXPLAIN 看执行计划,重点关注 type(应为 ref、range 或 const)、key(是否显示你建的索引名)、rows(预估扫描行数):
EXPLAIN SELECT * FROM logs WHERE level = 'ERROR' AND created_at > '2024-01-01';
- 如果
key是NULL,说明没走索引,检查字段类型是否隐式转换(比如varchar字段传了数字参数) - 如果
type是ALL,可能是索引顺序不对,或WHERE中用了函数(如DATE(created_at)),导致索引失效 - 注意
SELECT *可能触发回表,若只需要几个字段,考虑建覆盖索引(把SELECT字段全包含进索引)
索引不是越多越好,每个额外索引都会拖慢 INSERT/UPDATE/DELETE,而且占用磁盘和内存。真正卡住性能的往往不是缺索引,而是没看懂执行计划里那几行 rows 值意味着什么。









