text字段无法直接建普通b+树索引,因innodb要求索引键长度明确且可全量加载至16kb页内,而text值存于溢出页、仅留20字节指针,故必须指定前缀长度(如text_col(255));但前缀索引仅支持left like和order by,对%keyword等模糊查询无效,且存在区分度低、空间浪费、中文字符限制等问题;全文索引虽可行,却无法替代b+树功能,且建索引慢、更新代价高、分词受限;根本解法是避免将日志、html等非结构化数据存入text字段,改用冷表分离、对象存储或es等专用检索系统。

TEXT字段无法直接建普通B+树索引
MySQL的InnoDB引擎要求索引列必须能被完整加载进内存页(默认16KB),而TEXT类型数据默认不存于行内,而是以“指针+外部页”方式存储。这意味着CREATE INDEX idx_on_text ON t (text_col)会直接报错:ERROR 1170 (42000): BLOB/TEXT column 'text_col' used in key specification without a key length。你必须显式指定前缀长度,比如INDEX idx_on_text (text_col(255)),但这只是对前255字节建索引,后半部分完全不可查。
前缀索引实际效果差,且容易误判
即使加了前缀长度,也只覆盖开头固定字节数,对以下场景完全失效:
- 用
WHERE text_col LIKE '%keyword'查后缀 → 前缀索引无用 - 用
WHERE text_col LIKE '%keyword%'查中间内容 → 全表扫描 - 字段实际内容普遍短于前缀长度(如多数值只有50字节),但你设了
(500)→ 浪费索引空间,还拖慢INSERT/UPDATE - 字符集是utf8mb4时,1个中文占4字节,
(255)实际只能索引约63个汉字 → 容易超出预期
全文索引不是万能解,反而引入新瓶颈
虽然FULLTEXT能支持分词搜索,但它和普通索引完全不同:
- 不支持
LIKE、=或范围查询,只能用MATCH ... AGAINST - 建索引耗时极长:10万行含
TEXT的表,ALTER TABLE ... ADD FULLTEXT可能卡住数小时 - 更新代价高:每次
INSERT/UPDATE都要触发分词、倒排索引更新,QPS稍高就明显抖动 - 最小词长默认是4,搜“go”“AI”“OK”全命中不了,改
ft_min_word_len需重启MySQL
真正该做的不是“怎么索引TEXT”,而是“要不要放这里”
绝大多数生产事故不是因为不会建索引,而是把不该进数据库的文本硬塞进TEXT字段。比如日志、原始请求体、HTML源码、用户上传的富文本草稿——这些本就不该走主库读写路径。更合理的做法是:
- 拆表:把
TEXT字段单独拎到冷表,用JOIN按需关联,主表保持轻量 - 换存储:用对象存储(OSS/S3)存原文,DB里只留
url或hash,查时再拉 - 预处理:提取关键标签、摘要、分类ID等结构化字段,让查询落在
VARCHAR或INT上 - 真要搜内容:交给Elasticsearch或ZincSearch,别让MySQL扛全文检索
TEXT字段本身没毛病,问题出在把它当普通字段用。一旦它出现在WHERE、ORDER BY、GROUP BY或JOIN条件里,性能雪崩几乎是确定的。











