like '%keyword'在存储过程中加索引也无效,因b+树索引按字符串从左到右排序,无法定位末尾匹配起点,属物理结构硬限制;explain显示type为all或key为null即未走索引。

在存储过程中写模糊搜索,性能瓶颈几乎从不来自“是不是在存储过程里”,而来自 LIKE 模式本身是否可走索引、字段是否有匹配的索引结构、以及参数传入时是否触发隐式转换或全表扫描。
为什么 LIKE '%keyword' 在存储过程里加索引也无效
B+ 树索引按字符串从左到右排序,LIKE '%keyword' 要求匹配末尾,数据库无法定位起点——这不是 SQL 写得不够“巧”,是物理结构决定的硬限制。
-
EXPLAIN中type显示ALL或index、key为NULL,就是没走索引的铁证 - 哪怕你在存储过程里用
CONCAT('%', in_keyword)拼接,优化器照样放弃索引 -
UPPER(name) LIKE UPPER('%abc')这类函数包裹列的写法,100% 失效;应统一小写存 + 直接name LIKE 'abc%' - MySQL 5.7 可建生成列
name_rev VARCHAR(255) AS (REVERSE(name)) STORED+ 索引;8.0+ 更简单:CREATE INDEX idx_name_rev ON t((REVERSE(name)))
LIKE 'keyword%' 怎么写才真走索引
这是唯一能天然利用普通 B+ 树索引的场景,但极易因细节失效。
- 必须用
CONCAT(in_keyword, '%'),不能写成CONCAT('%', in_keyword)或CONCAT('%', in_keyword, '%') - 字段若有字符集/校对规则(如
utf8mb4_0900_as_cs),传入参数也要保持一致,否则隐式转换导致索引失效 - 联合查询时,把高选择性条件放前面:
WHERE status = 'active' AND name LIKE CONCAT(in_keyword, '%'),对应索引应为(status, name),而非单列name - 调用前务必
TRIM()参数,空格会让'张%'匹配不到'张三',还拉低索引选择性
什么时候该切到 MATCH ... AGAINST
当业务明确需要“包含关键词”“前后都模糊”“支持同义或拼音联想”时,LIKE 已不是优化问题,而是技术路径错误。
- 中文必须开
ngram插件并设ft_ngram_token_size = 2,否则搜单字(如“数”“据”)基本无结果 - 查询语句必须是
MATCH(col) AGAINST(in_keyword IN NATURAL LANGUAGE MODE),不能混用LIKE,也不能给in_keyword加% -
AGAINST不支持通配符前缀(*abc报错),但在BOOLEAN MODE下支持后缀(abc*) - 全文索引需提前建好,且字段类型要支持:
TEXT或VARCHAR,引擎为InnoDB或MyISAM
真正容易被忽略的是:虚拟列、全文索引、ngram 都需要 DDL 权限;上线前不确认账号权限,存储过程会直接报错。还有,ngram 对单字检索无效——比如搜“我”“你”,根本不会命中,这不是 bug,是分词机制决定的。











