text/blob字段不能直接建普通索引,因可能极大导致性能问题;必须指定前缀长度(如content(255)),但前缀索引不支持like '%xxx'、order by等;可用生成列+哈希(如sha2)建高效等值索引,或改用fulltext处理关键词搜索。

TEXT/BLOB 字段为什么不能直接建普通索引
MySQL 对 TEXT 和 BLOB 类型字段限制很死:除非指定前缀长度,否则不允许在它们身上建 INDEX 或 UNIQUE 索引。这是因为这类字段可能极大,全量索引会严重拖慢写入、膨胀索引文件,甚至让 B+ 树结构失效。
你试过 ALTER TABLE t ADD INDEX idx_content(content)?大概率报错 ERROR 1170 (42000): BLOB/TEXT column 'content' used in key specification without a key length —— 这就是 MySQL 在拦你。
- 只能加前缀索引,比如
ADD INDEX idx_content(content(255)),但 255 是字节数(非字符数),对 utf8mb4 实际最多覆盖 63 个汉字 - 前缀索引无法支持
ORDER BY、GROUP BY或LIKE '%xxx'这类无左前缀的查询 - 如果业务常查内容中间或结尾的子串(比如日志里匹配
"error code: 500"),前缀索引完全无效
用生成列 + 普通索引模拟“外部哈希索引”
所谓“外部哈希索引”,不是真的在 MySQL 外面搭 Redis,而是用 MySQL 5.7+ 的 GENERATED COLUMN 把大字段哈希后存成整数或短字符串,再对这个生成列建高效索引。
核心思路:把模糊/全文匹配需求,降维成等值查询。例如查某段文本是否出现过,不扫 content 全文,而是查它的 SHA256 前 16 字节 —— 这个值可建 INDEX,查询飞快。
- 添加生成列:
ALTER TABLE t ADD COLUMN content_hash CHAR(32) AS (SHA2(content, 256)) STORED - 立刻建索引:
CREATE INDEX idx_content_hash ON t(content_hash) - 查询时改写为:
SELECT * FROM t WHERE content_hash = SHA2('目标文本', 256) - 注意
STORED是必须的(不能用VIRTUAL),否则无法索引 - 哈希碰撞概率极低,但业务上仍建议加一层
AND content = '目标文本'做最终校验
什么时候该用全文索引而不是哈希
哈希适合「是否存在」的精确匹配,但如果你要搜关键词、支持分词、需要相关性排序(比如“mysql 优化 slow query”),FULLTEXT 是更正统的选择 —— 尤其在 InnoDB 表中已原生支持。
- 建全文索引:
ALTER TABLE t ADD FULLTEXT(content)(仅限CHAR/VARCHAR/TEXT) - 查询用:
SELECT * FROM t WHERE MATCH(content) AGAINST('优化' IN NATURAL LANGUAGE MODE) - 注意:全文索引默认忽略少于 4 字符的词(
ft_min_word_len=4),且停用词表会影响结果 - 性能上,全文索引比
LIKE '%xxx%'快得多,但比哈希索引慢一个数量级;写入开销也明显更高 - 不支持中文分词(除非配 ngram 或使用第三方插件),纯靠空格/标点切分 —— 这是大多数踩坑的源头
别碰 LIKE '%xxx%',除非你确认数据量永远小于一万行
这是最常被当“捷径”用、实则最伤性能的操作。只要 LIKE 左边带通配符(%xxx),哪怕右边有索引,MySQL 也基本放弃走索引,退化为全表扫描。
- 哪怕你给
content(500)加了前缀索引,WHERE content LIKE '%error%'依然不会用它 - EXPLAIN 出来
type: ALL、rows接近表总行数?基本可以判定是这个原因 - 替代方案只有三个:哈希列(等值)、全文索引(关键词)、或者把检索逻辑移到应用层(如用 Elasticsearch 同步内容)
- 如果真要保留
LIKE,至少确保是左前缀形式:content LIKE 'ERROR:%',这样能用上前缀索引
哈希列方案看着绕,但上线后查一条从 2s 变成 20ms,这种收益是实打实的。真正容易被忽略的是哈希值存储长度和字符集 —— CHAR(32) 在 utf8mb4 下占 128 字节,而 BINARY(16) 存 MD5 更省空间,只是得用 HEX(MD5(content)) 配合,别搞混编码方式。










