TEXT/BLOB字段查得慢是因为MySQL仅支持前缀索引,若前缀长度不足(如关键词在截断位置之后)、LIKE '%xxx%' 无法使用B-tree索引、大字段导致IO和内存压力大,需结合前缀长度优化、字段拆分、FULLTEXT或外部搜索引擎综合解决。

为什么 TEXT 或 BLOB 字段加了索引还是查得慢
因为 MySQL 默认不给完整 TEXT/BLOB 字段建索引——它只允许前缀索引,而你可能没意识到“前缀长度”选错了。比如设成 INDEX(content(10)),但实际匹配关键词在第 20 个字符之后,这个索引就完全失效。
常见错误现象:EXPLAIN 显示 key_len 很小、type 是 ALL、查询耗时稳定在几秒以上,哪怕数据只有几千行。
- 前缀长度必须覆盖绝大多数查询关键词的起始位置,不是随便填个数字
-
utf8mb4下一个汉字占 4 字节,content(50)实际可能只存 12 个汉字,别按“字符数”拍脑袋 - 如果常做
LIKE '%关键词%'全文模糊查,前缀索引根本没用,得换方案
怎么选对前缀长度:用 SELECT 算出来,别猜
直接统计真实数据中“最短唯一前缀”的分布,比凭经验靠谱得多。比如你想加速 WHERE content LIKE 'xxx%' 这类查询,就得知道前多少字节能区分出 95% 的值。
实操建议:
- 先抽样看数据分布:
SELECT LEFT(content, 100) AS prefix, COUNT(*) FROM articles GROUP BY prefix ORDER BY COUNT(*) DESC LIMIT 5;
- 再跑聚合统计,找平衡点:
SELECT len, COUNT(*) cnt FROM (SELECT LEAST(LENGTH(content), 200) AS len FROM articles) t GROUP BY len ORDER BY cnt DESC;
- 最终建索引时,长度建议略大于“高频前缀最大长度”,比如算出来 85% 的内容前 120 字节就足够区分,那就用
content(150)
LIKE '%xxx' 和 LIKE '%xxx%' 压根不能靠前缀索引
只要 LIKE 模式以 % 开头,MySQL 就没法用任何 B-tree 索引(包括前缀索引),只能全表扫描。这时候加索引不仅没用,还拖慢写入和占用空间。
真实使用场景里,这类查询往往出现在后台搜索或日志检索,但用户其实并不需要“包含任意位置”的结果,而是想查“标题含关键词”或“开头是某段文本”。可以拆解处理:
- 把关键元信息单独抽成
VARCHAR字段(如title_snippet),加普通索引 - 用
FULLTEXT索引替代——但注意它只支持MyISAM和InnoDB(5.6+),且对停用词、最小词长敏感 - 真要查中间内容,考虑把
BLOB内容同步到Elasticsearch或Sphinx,别硬扛在 MySQL 里
大字段本身就在拖慢查询,光加索引治标不治本
即使索引生效,每次 SELECT * 或 SELECT content 都要把几 MB 的 BLOB 从磁盘读进内存、网络传回客户端,IO 和带宽压力远超索引查找本身。
容易被忽略的细节:
- 如果只是校验是否存在或取长度,用
SELECT LENGTH(content)而不是SELECT content - 把大字段挪到独立表(如
articles_content),主表只留 ID 关联,能显著减少主查询的 I/O 和锁竞争 -
innodb_log_file_size和innodb_buffer_pool_size如果没调大,大字段更新会频繁刷脏页,连带拖慢其他查询
真正卡住的,往往不是“找不到索引”,而是“找到了也得搬一整块砖才能进门”。优化得从存储结构和访问模式一起动刀,单靠 ADD INDEX 解不了。











