%匹配任意长度(含零)字符,_匹配单个字符;误用会导致漏数据,如查“张”开头却写'张_'只匹配两字姓名,需注意转义、索引失效、collation影响及null不匹配。

LIKE 通配符怎么用才不会查错数据
LIKE 的核心就两个通配符:% 匹配任意长度(含零)字符,_ 匹配单个字符。但很多人一写 WHERE name LIKE '%张%' 就以为万事大吉,结果漏掉带空格、全角符号或大小写敏感的记录。
常见错误现象:查“李四”,却没命中数据库里存的 ' 李四 '(首尾空格);查“test”,匹配不到 'TEST'(大小写不一致);用 _ 时误以为能跨字节匹配中文——其实它只认一个字符,而 UTF-8 下一个汉字占 3 字节,_ 无法匹配。
- 中文场景慎用
_,优先用%;真要定位第 2 个字是“明”的人名,写成WHERE name LIKE '_明%'在 MySQL 默认 utf8mb4 排序规则下是可行的,但 PostgreSQL 需确认 collation 支持单字符语义 - 前置通配符(如
'%abc')无法走索引,查询会全表扫描;能写成'abc%'就别写反了 - 想查真实存在的
%或_字符?必须用ESCAPE:例如WHERE tag LIKE '100\%' ESCAPE '\'
MySQL 和 PostgreSQL 的 LIKE 行为差异在哪
MySQL 默认不区分大小写(依赖 collation,如 utf8mb4_0900_as_cs 才区分),PostgreSQL 默认区分大小写。这意味着同样一句 WHERE title LIKE 'sql%',在 MySQL 可能命中 “SQL Guide”,在 PostgreSQL 就不会。
另一个关键区别:PostgreSQL 的 ILIKE 是原生不区分大小写的替代方案,MySQL 没这个关键字,得靠 COLLATE utf8mb4_general_ci 或函数包装(如 LOWER(title) LIKE LOWER('sql%'))。
- MySQL 中
LIKE对 NULL 值返回 FALSE,不是 UNKNOWN;所以WHERE col LIKE '%'不会包含 NULL 记录 - PostgreSQL 允许在
LIKE中使用 Unicode 字符类(需开启 ICU collation),MySQL 不支持 - 两者都支持索引加速前缀匹配(
'abc%'),但 MySQL 的前缀索引长度受字段定义限制,PostgreSQL 的表达式索引更灵活
模糊查询慢?先看执行计划再动手
加了 LIKE 就变慢,第一反应不该是“换 ES”,而是看 EXPLAIN 输出有没有用上索引。尤其注意 type 列是否为 range 或 ref,而不是 ALL。
如果发现走了全表扫描,可能原因不止是通配符位置:字段没索引、索引被隐式转换(比如对 INT 字段用字符串 LIKE)、或者用了函数包裹字段(UPPER(name) LIKE 'A%' 直接废掉索引)。
- 给经常模糊查询的字段建前缀索引:如
CREATE INDEX idx_name_prefix ON users (name(20)),20 要覆盖大部分查询前缀长度 - 避免在
LIKE左侧用函数,改写成常量在右:把WHERE UPPER(name) LIKE 'ABC%'换成WHERE name >= 'abc' AND name (配合对应 collation) - PostgreSQL 可用
pg_trgm扩展支持%word%类型的高效模糊匹配,MySQL 8.0+ 可用全文索引 +MATCH ... AGAINST替代部分场景
LIKE 遇到 JSON 或数组字段怎么办
直接对 JSON 字段用 LIKE(如 WHERE meta LIKE '%\"status\": \"active\"%')既不可靠又难维护。JSON 结构稍一变动,正则式就失效;而且无法利用 JSON 索引。
正确做法取决于数据库版本和字段用途:MySQL 5.7+ 应用 JSON_CONTAINS() 或 ->> 提取后判断;PostgreSQL 则用 ->> 或 @> 操作符,而非字符串匹配。
- MySQL 示例:查 status 为 active 的记录,用
WHERE JSON_EXTRACT(meta, '$.status') = '"active"'或更简洁的WHERE meta->>'$.status' = 'active' - PostgreSQL 示例:等价写法是
WHERE meta->>'status' = 'active';若需模糊匹配值内部,再套ILIKE,如(meta->>'desc') ILIKE '%urgent%' - 数组字段同理:MySQL 用
JSON_CONTAINS(tags, '"php"),PostgreSQL 用'php' = ANY(tags),都比LIKE '%php%'安全且可索引
LIKE 扫一遍字符串,不如一开始就拆成关联表或启用 GIN 索引。











