%匹配任意长度字符,\_仅匹配单个字符;需转义才能查字面下划线;前置%导致全表扫描;中文检索优先用ngram全文索引;LIKE参数须在代码中加通配符并转义特殊字符;仅后缀通配符可走索引。

LIKE 里 % 和 _ 到底怎么用才不翻车
百分号 % 匹配任意长度(含零)字符,下划线 _ 只匹配单个字符——这是最常写错的起点。比如想查“张三丰”,却写成 WHERE name LIKE '张%丰',表面看没问题,但若数据库里存的是“张三 丰”(中间有空格)或“张三丰 ”(尾部有空格),就查不到。更隐蔽的是,_ 在 MySQL 里是通配符,不是普通下划线;如果真要查用户名字里带下划线(如 user_name),必须转义:LIKE 'user\_name' ESCAPE '\'。
- 默认不区分大小写(取决于字段 collation),但
utf8mb4_0900_as_cs这类大小写敏感排序规则下,'ABC'≠'abc' -
%放开头(如LIKE '%关键词')会强制全表扫描,没索引可走,大数据量时延迟明显 - 中文模糊查常用
LIKE '%某地%',但若字段是TEXT类型且没建前缀索引,性能比VARCHAR更差
中文搜索用 LIKE 还是全文索引
纯 LIKE 查中文基本靠扫表,尤其带前置 % 时。MySQL 原生全文索引(FULLTEXT)支持中文需搭配 ngram 插件(5.7+),且最小分词长度默认为 2——意味着“我”“你”这种单字搜不到。开启方式是建表时加 FULLTEXT(name),查询用 MATCH(name) AGAINST('上海' IN NATURAL LANGUAGE MODE)。但注意:ngram 不支持布尔模式下的通配符,AGAINST('上*' IN BOOLEAN MODE) 无效。
- LIKE 适合简单、低频、数据量小的场景(如后台管理搜用户昵称)
- FULLTEXT 适合高频、多关键词、需相关性排序的场景(如文章标题检索)
- 两者都不解决“同音不同字”(如“张三”和“章三”),得靠应用层补拼音转换
参数化查询里怎么安全拼 LIKE 条件
直接字符串拼接 "%"+keyword+"%" 是 SQL 注入温床。ORM 如 MyBatis 用 #{} 是预编译,但 LIKE 的通配符必须在参数值里,不能写在 SQL 模板中。正确做法是:在代码里手动加 %,再传给预编译参数。
- 错误写法:
WHERE name LIKE '%#{keyword}%'—— MyBatis 会把%当字面量,查不到任何东西 - 正确写法:
WHERE name LIKE #{keyword},Java 侧传入"%张%";或用 MyBatis 的concat():WHERE name LIKE CONCAT('%', #{keyword}, '%') - 如果 keyword 本身含
%或_(比如查文件名report_2024.sql),必须先 escape:keyword.replace("_","\_").replace("%","\%"),再配合ESCAPE '\'
为什么加了索引 LIKE 还慢
只有当 LIKE 模式不以通配符开头时,B+ 树索引才能生效。例如 name LIKE '张%' 可走索引,但 name LIKE '%张%' 不行。另外,联合索引最左前缀原则依然适用:INDEX(status, name) 对 WHERE status=1 AND name LIKE '张%' 有效,但对 WHERE name LIKE '张%' 无效。
- 前缀索引(如
INDEX(name(10)))能节省空间,但LIKE '张%'仍可用,而LIKE '%三%'依旧失效 - 函数索引(MySQL 8.0+)可绕过部分限制,比如
CREATE INDEX idx_name_lower ON t1 ((LOWER(name))),但 LIKE 本身不触发函数索引优化 - EXPLAIN 看
type是range才算走了索引,ALL就是全表扫
真正卡住人的往往不是语法,而是没意识到 LIKE 的索引边界和字符集隐式转换——比如字段是 utf8mb4,但连接字符集设成 latin1,会导致索引失效且无报错。










