LIKE '%abc'慢是因为无法利用B+树索引做右模糊匹配,导致全表扫描;EXPLAIN显示type: ALL、key: NULL;仅LIKE 'abc%'能有效走索引;全文索引与LIKE机制不同,适用于关键词搜索而非通配位置控制。

LIKE带前导%为什么慢得像卡住
因为数据库无法用索引的B+树结构做“右模糊”(%abc)的范围查找,只能全表扫描。即使字段上有索引,LIKE '%abc' 也基本等于没用——优化器会直接放弃走索引。
常见错误现象:EXPLAIN 显示 type: ALL、key: NULL,rows 数等于表总行数;查询耗时从几毫秒飙到几秒甚至更久。
- 只有
LIKE 'abc%'(左模糊)能有效利用索引前缀匹配 -
LIKE '%abc%'(双向模糊)在绝大多数场景下都触发全表扫描 - MySQL 8.0+ 对
LIKE 'ab%c'这类含中间通配符的尝试做了部分优化,但实际效果依赖数据分布,不建议依赖
用FULLTEXT替代LIKE的实操门槛
全文索引不是LIKE的“升级版”,而是另一套机制:它对文本分词建倒排索引,适合关键词搜索,但不保证顺序、不支持通配符位置控制,且默认忽略停用词和短词(如少于4字符的词在MySQL默认ft_min_word_len=4下不会被索引)。
使用场景:搜索文章标题/正文中的关键词组合,比如“数据库 优化”,而不是“以‘数据库’开头的字段”。
- 建表时加
FULLTEXT(title, content),或后续用ALTER TABLE ADD FULLTEXT - 查询必须用
MATCH(title, content) AGAINST('关键词' IN NATURAL LANGUAGE MODE),不能混用LIKE - 注意:中文需搭配
ngram插件(MySQL)或改用zhparser(PostgreSQL),否则分词失效 -
AGAINST('abc*' IN BOOLEAN MODE)支持末尾通配,但不支持前导通配(*abc非法)
前导%又绕不开?试试生成式前缀或函数索引
当业务真要查“结尾含某字符串”(如邮箱域名 LIKE '%@example.com'),硬扛全表扫描不是唯一解。核心思路是:把“后缀匹配”转成“前缀匹配”,靠额外字段或表达式索引破局。
- 加冗余字段存反转字符串:
email_reversed VARCHAR(255),写入时自动填REVERSE(email),查询改写为email_reversed LIKE 'moc.elpmaxe@%',再对该字段建普通索引 - MySQL 8.0+ / PostgreSQL 可直接建函数索引:
CREATE INDEX idx_email_domain ON users ((SUBSTRING_INDEX(email, '@', -1))),然后查SUBSTRING_INDEX(email, '@', -1) = 'example.com' - 避免在WHERE里对字段用函数:
WHERE SUBSTRING(email, -10) = 'example.com'仍会全表扫——必须让函数出现在索引定义侧,而非查询侧
LIKE性能陷阱:COLLATION和大小写隐式转换
即使写了 LIKE 'abc%',如果字段是 utf8mb4_unicode_ci 而查询条件含非ASCII字符,或字段类型与参数类型不一致(如字段是 VARCHAR,参数传了 TEXT),可能触发隐式转换,导致索引失效。
- 检查执行计划里
possible_keys是否包含预期索引,key是否真的用了它 - 统一字符集和排序规则:字段、连接、客户端三端
COLLATE尽量一致,尤其避免_ci和_bin混用 - 用
SHOW VARIABLES LIKE 'collation%'确认服务端默认值,必要时显式声明:WHERE name COLLATE utf8mb4_bin LIKE 'abc%' - 数值型字段别用字符串LIKE查:
id LIKE '123%'会让id被转成字符串,索引失效;应改用范围:id BETWEEN 1230 AND 1239
真正难的不是选哪个方案,而是想清楚你到底在查什么:是“找包含关键词的文档”,还是“找以某串字符结尾的ID”,或是“用户输入了不完整的前缀想实时提示”。不同目标对应不同技术路径,强行用全文索引去扛前缀补全,或者给日志表每个字段都加函数索引,反而让问题更重。










