like '%abc'无法走索引是因为b+树仅支持左前缀匹配,无法定位后缀扫描起点,只能全表扫描;可通过反向索引(如reverse(name))或函数索引优化。

LIKE 本身不慢,慢是因为你写的模式根本没走索引——尤其是 LIKE '%xxx' 或 LIKE '%xxx%',EXPLAIN 里 type 一定是 ALL,别指望加个普通索引就能救。
为什么 LIKE 'abc%' 能走索引,而 LIKE '%abc' 不能?
B+ 树索引按字段完整值排序,只能快速定位“以某前缀开头”的数据。一旦通配符在左边,数据库就无法从索引树根节点往下有序跳转,只能扫全表。
-
LIKE 'abc%':索引能直接跳到'abc'开头的叶节点区间,type 是range -
LIKE '%abc':哪怕字段有索引,执行计划也显示 type =ALL,因为“以 abc 结尾”无法利用 B+ 树的有序性 -
LIKE '%abc%':同理,前后都模糊,索引完全失效
怎么让 LIKE '%abc' 快起来?用反向索引
核心思路是把“后缀匹配”转成“前缀匹配”:存一份反转字段,再对它建普通索引。
- 添加存储列:
ALTER TABLE users ADD COLUMN name_rev VARCHAR(100) AS (REVERSE(name)) STORED; - 建索引:
CREATE INDEX idx_name_rev ON users (name_rev); - 查的时候写成:
WHERE name_rev LIKE REVERSE('%abc');(即WHERE name_rev LIKE 'cba%') - 注意:这个方法只对
LIKE '%abc'有效;LIKE '%abc%'反转后仍是'%cba%',照样没法走索引
中文搜单字或短词,FULLTEXT 索引必须配 ngram 分词器
默认的 FULLTEXT 对中文几乎无效——最小词长是 4,停用词(如“的”“了”)直接被过滤,搜“李”或“AI”根本命中不了。
- 建全文索引时显式指定分词器:
CREATE FULLTEXT INDEX idx_content_ngram ON articles(content) WITH PARSER ngram; - 查询必须用
MATCH() AGAINST(),写成WHERE content LIKE '%李%'就算有全文索引也白搭 - 查不到结果先确认停用词:
SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD; -
ngram_token_size默认为 2,搜两个字以上才可能命中;若需搜单字,得调小该参数(需重启 MySQL)
别信 INSTR()、LOCATE()、POSITION() 能提速
它们只是 LIKE '%xxx%' 的语法糖,执行计划里照样是 type: ALL。MySQL 不会对函数结果自动建索引,除非你手动创建函数索引(MySQL 8.0+)。
- 想用
LOWER()实现大小写不敏感?先建函数索引:CREATE INDEX idx_name_lower ON users ((LOWER(name))); - 想用
REVERSE()加速后缀查询?也可以直接建函数索引:CREATE INDEX idx_name_reverse ON users ((REVERSE(name))); - 但注意:函数索引只在 WHERE 条件中**原样写出该函数**时才生效,比如
WHERE REVERSE(name) LIKE 'cba%';写成WHERE name LIKE '%abc'依然不走
真正卡住性能的,往往不是“会不会写”,而是没看清执行计划里 key 列是不是 NULL、type 是不是 ALL。只要看到这两项,说明当前写法已经放弃索引——这时候该换方案,而不是调优语句本身。










