mysql不允许对blob/text字段建普通索引,因可能过大影响性能,仅支持前缀索引;需指定字节长度(如100),innodb上限3072字节;应通过选择性分析确定合理前缀长度,并注意其仅优化like 'xxx%'和等值查询。

为什么 BLOB 字段不能直接建普通索引
MySQL 不允许对未指定长度的 BLOB、TEXT 类型字段直接创建完整索引,会报错:ERROR 1170 (42000): BLOB/TEXT column 'content' used in key specification without a key length。这是因为这类字段可能极大,索引全量内容既不现实,也会严重拖慢写入和索引维护性能。前缀索引是唯一可行的索引方式——只索引字段开头若干字节。
CREATE INDEX 时如何指定前缀长度
语法上必须显式给出字节数(不是字符数),且单位是字节,对 UTF8MB4 编码尤其关键:一个中文字符占 4 字节,设前缀为 100 就只覆盖最多 25 个汉字。
- 基本写法:
CREATE INDEX idx_blob_prefix ON tbl (blob_col(100)); - 前缀长度必须是整数,不能带单位(如
100b或100 bytes) - 最大允许值取决于存储引擎:InnoDB 最大支持 3072 字节(单列)、MyISAM 是 1000 字节
- 若字段实际内容普遍短于前缀长度,多余部分不参与索引,但也不会报错
怎么选够用又不过长的前缀长度
核心目标是让前缀具备足够区分度,避免大量重复前缀导致索引失效。不能拍脑袋定 50 或 100,得看数据分布。
- 先统计不同前缀长度下的重复率:
SELECT COUNT(*) AS total, COUNT(DISTINCT LEFT(blob_col, 50)) AS unique_50 FROM tbl; - 计算选择性:
unique_50 / total,建议 ≥ 0.95;再试 40、30,直到选择性开始明显下降 - 注意:如果
blob_col存的是 JSON 或 HTML,开头几十字节常是固定结构(如{"id":或/code>),会导致低选择性——这时需跳过头部,改用函数索引(MySQL 8.0+):<code>CREATE INDEX idx_json_id ON tbl ((CAST(JSON_EXTRACT(blob_col, '$.id') AS UNSIGNED))); - 用
EXPLAIN验证是否走索引:EXPLAIN SELECT * FROM tbl WHERE blob_col LIKE 'xxx%';,确保key列显示你的前缀索引名
前缀索引的隐性代价和绕不开的限制
它不是银弹。前缀索引只加速 LIKE 'xxx%' 和等值匹配(=),对 LIKE '%xxx'、LIKE '%xxx%'、ORDER BY blob_col 完全无效。
- 无法用于
MIN()/MAX()聚合,因为索引不包含完整值 - 排序和分组操作仍需回表读取完整
BLOB值,IO 开销大 - 如果业务需要按大字段内容做模糊搜索或全文检索,应考虑
FULLTEXT索引(仅限 MyISAM / InnoDB 的 CHAR/VARCHAR)或外接 Elasticsearch - 备份与复制延迟可能因索引体积变小而改善,但主从一致性校验工具(如 pt-table-checksum)仍需比对完整字段值,前缀索引不降低校验成本
真正难的不是算出那个“最优前缀数字”,而是确认查询模式是否真的能被前缀索引覆盖——很多以为能优化的 WHERE 条件,其实根本走不上这个索引。











