什么时候应该用前缀索引而不是完整列索引长度限制怎么定

文章导读
当 MySQL 表中的字符串列(如 VARCHAR、TEXT)长度较大且查询主要匹配前缀时,应该使用前缀索引。如果完整列索引超过存储引擎限制(如 InnoDB 默认 767 字节)或占用过多空间,需指定前缀长度。风险边界是前缀索引无法用于 ORDER BY、GROUP BY 和覆盖索引扫描。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

当 MySQL 表中的字符串列(如 VARCHAR、TEXT)长度较大且查询主要匹配前缀时,应该使用前缀索引。如果完整列索引超过存储引擎限制(如 InnoDB 默认 767 字节)或占用过多空间,需指定前缀长度。风险边界是前缀索引无法用于 ORDER BY、GROUP BY 和覆盖索引扫描。

先说结论:前缀索引适合长字符串字段且查询条件为前缀匹配的场景,长度选择需平衡区分度与存储限制。

  • 适合:VARCHAR 或 TEXT 类型列,查询使用 LIKE 'prefix%' 或等值匹配前缀。
  • 重点看:索引选择性(区分度),需通过 SQL 计算不同长度下的 DISTINCT 比例。
  • 别忽略:前缀索引不支持排序、分组和覆盖索引,联合索引中长字段需放在最后。

命令速用版

创建前缀索引直接在列名后指定字符长度,建表或修改表结构均可执行。

-- 建表时定义
CREATE TABLE users (
  id INT PRIMARY KEY,
  email VARCHAR(255),
  INDEX idx_email (email(10))
);

-- 已有表添加索引
CREATE INDEX idx_email_prefix ON users (email(10));

-- 联合索引(长字段放最后)
CREATE INDEX idx_status_email ON users (status, email(191));

为什么会这样

使用前缀索引的核心原因是突破索引长度限制并节省存储空间。InnoDB 引擎默认单索引最大长度为 767 字节,utf8mb4 字符集下约等于 191 个字符,超过该长度必须指定前缀。

完整列索引对于长字符串会占用大量磁盘空间和内存,导致索引树过高,增加 I/O 消耗。前缀索引仅索引列值的前 N 个字符,能减小索引体积,提高插入速度和查询效率。但代价是索引选择性可能降低,且无法利用索引完成排序操作。

什么时候应该用前缀索引而不是完整列索引长度限制怎么定

分步处理

第一步是评估字段区分度,确保前缀长度足够唯一标识数据。

执行 SQL 计算不同前缀长度的区分度,公式为 distinct_count / total_count,结果越接近 1 越好。

SELECT COUNT(DISTINCT LEFT(email, 10)) / COUNT(*) FROM users;
SELECT COUNT(DISTINCT LEFT(email, 12)), COUNT(DISTINCT email) FROM users;

第二步是创建索引,注意字符集影响。非二进制字符串(VARCHAR)前缀按字符数计算,二进制字符串(BLOB)按字节数计算。

第三步是检查索引定义,确保长度参数已生效。如果字段类型是 TEXT 而忘记加长度,MySQL 可能自动忽略索引定义。

怎么验证是否生效

使用 SHOW INDEX 命令查看 Sub_part 列,确认前缀长度是否符合预期。

什么时候应该用前缀索引而不是完整列索引长度限制怎么定
SHOW INDEX FROM users WHERE Key_name = 'idx_email';

Sub_part 列显示数字(如 10 或 191)表示前缀长度生效,显示 NULL 表示全列索引。如果建了 email(191) 却看到 Sub_part 是 NULL,说明建索引语句没生效。

使用 EXPLAIN 分析查询语句,确认 type 列为 ref 或 range,且 key 列显示创建的索引名。如果查询条件未用上最左前缀,可能仍走全表扫描。

常见坑

联合索引中长字段带前缀必须置于最后,否则可能报错或查询效率受损。例如 (status, email(191)) 合法,但 (email(191), status) 在某些版本受限。

前缀索引不能作为唯一索引,因为前缀相同的数据会被视为重复。如果业务要求唯一性,必须使用完整列索引。

什么时候应该用前缀索引而不是完整列索引长度限制怎么定

长度单位易混淆,utf8mb4 下 1 个中文等于 1 个字符而非 3 个字节,定义长度时按字符数指定,但受限于总字节数上限。

常见问题

前缀索引能用于 ORDER BY 吗?

不能。MySQL 无法利用前缀索引完成排序和分组操作,这类查询会触发文件排序。

如何确定最佳前缀长度?

通过逐步增加长度测试区分度,当区分度达到 90% 以上且不再显著增长时,即为合适长度。

所有字符串字段都适合前缀索引吗?

不适合。如果字段本身很短或前缀重复率极高(如大量邮箱同一域名),前缀索引优势不明显。

参考来源

  • mysql 中前缀索引的使用方法与限制
  • 技术分享 | MySQL 索引长度限制的案例
  • 如何在 MySQL 中为特定列增加前缀索引_在 INDEX 定义中指定长度