SQL LIKE 查询从入门到工程实践:索引优化、通配符转义与注入防护
2026/9/8 6:12:04 网站建设 项目流程

SQL 里的LIKE应该是接触数据库管理系统时最早遇到的查询关键字之一。很多教程会告诉你“%代表任意多个字符,_代表一个字符”,然后给两个例子就结束了。但实际在业务里写LIKE,会碰到大小写、转义、索引失效、慢查询、注入风险、通配符误匹配等一系列问题。这篇就把LIKE从语法到性能、从安全到批量任务完整拆一遍,重点看它能不能走索引、什么时候不能走、怎么在真实业务里安全地使用它。

这次我们只围绕一件事:LIKE的完整用法和工程化实践。看完你不仅能写对LIKE查询,还能理解LIKE在慢 SQL 优化和 SQL 注入防护这两个高频场景里的位置。

文章会按“核心语法 -> 适用场景 -> 环境准备 -> 功能测试 -> 性能分析 -> 接口/批量任务 -> 安全边界 -> 问题排查 -> 最佳实践”的顺序展开。每个部分都配可执行的 SQL 或代码示例,建议收藏备用。


1. LIKE 核心能力速览

能力项说明
所属范畴数据库管理系统中的条件查询关键字
核心功能字符串模式匹配,支持通配符%_
通配符%匹配任意长度字符串(含空串),_匹配单个字符
转义方式ESCAPE子句自定义转义字符
大小写敏感度取决于数据库排序规则(collation),MySQL 默认不敏感,PostgreSQL 敏感
索引使用前缀匹配(LIKE 'abc%')可走索引,前导通配符(LIKE '%abc')通常索引失效
替代方案LOCATEINSTRPOSITION、全文索引、正则表达式
典型风险前导通配符导致全表扫描;未转义的通配符导致 SQL 注入或误匹配
适合场景模糊搜索、日志过滤、批量数据匹配、业务编码规则校验

LIKE功能很简单,真正的复杂度在“能不能走索引”“怎么防注入”“怎么批量执行”这些工程问题上。


2. 适用场景与使用边界

2.1 适合场景

  • LIKE最适合做模糊匹配,例如搜索用户名、商品名、订单号片段、文件名前缀。
  • 配合ESCAPE可以做特殊字符精确包含查询,比如查询包含%_的文本。
  • 在数据清洗场景中,LIKE常用来识别“包含某个关键字”的记录,再配合UPDATEDELETE处理。
  • 批量任务中,LIKE常用于按模式筛选数据,例如筛选某时间段生成的文件名、某前缀的订单号。

2.2 不适合场景

  • 大规模全文搜索。数据量超过百万级,LIKE '%关键词%'几乎无法走索引,应该优先考虑全文索引或 Elasticsearch 等搜索引擎。
  • 复杂模式匹配。如果需求是“匹配邮箱格式”“匹配手机号”,建议使用数据库的正则表达式函数。
  • 高频核心路径查询。LIKE的模糊匹配语义对索引不友好,核心接口应避免用前导通配符查询。

2.3 使用边界与安全提醒

  • 涉及用户输入时,LIKE%_需要特殊处理。如果直接拼接进 SQL,会带来 SQL 注入风险。
  • 在涉及个人隐私、肖像、声音、文本等数据查询时,必须确认数据来源合法、使用范围合规。
  • 使用LIKE做数据匹配前,要确认字段的字符集和排序规则,否则可能出现中文匹配不到、大小写不敏感但预期敏感等问题。
  • 禁止在未授权数据库上执行LIKE扫描测试。所有测试应在本地测试库中进行。

3. 环境准备与 SQL 执行工具

LIKE的语法在所有主流数据库管理系统(MySQL、PostgreSQL、SQL Server、SQLite)中基本通用,以下验证方案以 MySQL 为主,兼容其他数据库。

3.1 环境检查清单

检查项推荐要求
操作系统Windows / Linux / macOS 均可
数据库MySQL 5.7+ 或 MySQL 8.0+
客户端mysql 命令行或 DBeaver / Navicat
测试库单独的本地测试库,避免影响正式数据
字符集utf8mb4,避免中文乱码影响 LIKE 匹配结果

3.2 创建测试表并写入样例数据

先创建一个简单的用户表,用于后续所有 LIKE 测试:

CREATE DATABASE IF NOT EXISTS like_test DEFAULT CHARACTER SET utf8mb4; USE like_test; CREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, email VARCHAR(100), remark VARCHAR(200) ); INSERT INTO users (name, email, remark) VALUES ('Alice', 'alice@example.com', 'VIP member'), ('Bob', 'bob@example.com', 'normal user'), ('Charlie', 'charlie@test.org', 'VIP user'), ('David', 'david@example.net', 'test account'), ('Eve', 'eve@test.org', 'VIP'), ('Frank', 'frank@example.com', 'internal 100% system'), ('Grace', 'grace@test.org', 'admin_vip_user');

插入完成后,先验证基础数据:

SELECT * FROM users;

到这里,测试环境已经就绪。下面所有测试都基于该表。


4. LIKE 语法详解与功能测试

4.1 基础语法

LIKE的基本语法:

SELECT 字段列表 FROM 表名 WHERE 字段 LIKE 模式;

模式中可以使用两个通配符:

通配符含义
%匹配任意数量的字符,包括 0 个字符
_匹配任意 1 个字符

测试用例 1:查询所有邮箱以example.com结尾的用户。

SELECT id, name, email FROM users WHERE email LIKE '%example.com';

预期结果:AliceBobFrank的邮箱都以example.com结尾,其余数据不返回。

测试用例 2:查询名字中第二个字符是a的用户。

SELECT id, name FROM users WHERE name LIKE '_a%';

预期的_匹配任意一个字符,第二个字符为a,后续可以有任意字符。David符合条件,因为D是第一个字符,a是第二个字符。

测试用例 3:查询remark中同时包含VIPuser的记录。

SELECT * FROM users WHERE remark LIKE '%VIP%user%';

这里隐式依赖顺序,只要文本中先出现VIP后出现user就可以匹配到。

4.2 转义通配符测试

业务中经常要查“包含百分号”或“包含下划线”的文本。因为%_是通配符,必须使用ESCAPE指定转义字符,默认转义字符是反斜杠\,但不同数据库支持度不一样。推荐显式指定。

测试用例 4:查询remark中包含字面量100%的记录。

SELECT * FROM users WHERE remark LIKE '%100\%%' ESCAPE '\\';

如果写成:

SELECT * FROM users WHERE remark LIKE '%100%%';

会导致全表任意包含100的记录都匹配成功,而且行为不符合预期。

这里要注意,MySQL 默认转义字符是反斜杠,但如果sql_mode包含NO_BACKSLASH_ESCAPES,反斜杠不再作为转义符。最稳妥的方式是用ESCAPE显式指定一个字符,比如#

SELECT * FROM users WHERE remark LIKE '%100#%%' ESCAPE '#';

其中第一个#%表示字面量百分号,最后的%表示任意后续字符。

4.3 大小写敏感性测试

大小写是否敏感取决于排序规则。

在 MySQL 中:

  • utf8mb4_general_ci不区分大小写,LIKE 'alice%'能匹配Alice
  • utf8mb4_bin区分大小写,LIKE 'alice%'匹配不到Alice

测试方法:

SELECT id, name FROM users WHERE name LIKE 'a%';

如果结果包含Alice,说明当前排序规则不区分大小写。

在 PostgreSQL 中:

SELECT id, name FROM users WHERE name LIKE 'a%';

默认LIKE区分大小写,Alice不会被匹配。如果要用不区分大小写的匹配,在 PostgreSQL 中使用ILIKE或转为小写。

在 SQL Server 中,大小写由数据库排序规则决定,通常安装时默认不区分。

4.4 反向匹配

NOT LIKE用于排除匹配某个模式的记录。

测试用例 5:查询邮箱不以example.com结尾的用户。

SELECT id, name, email FROM users WHERE email NOT LIKE '%example.com';

注意NOT LIKE在字段为NULL时返回UNKNOWN,过滤后不会出现在结果中。如果遇到空值问题,需要补充IS NULL判断。


5. LIKE 性能分析与慢 SQL 排查

字符串匹配在数据量大的时候很容易变成慢 SQL。这一节重点讲LIKE的索引使用规则和排查方法。

5.1 什么情况下 LIKE 能走索引

结论是:只要模式以固定前缀开头,且匹配字段上有索引,LIKE就可以走索引

用一个实验验证。先给email字段加索引:

ALTER TABLE users ADD INDEX idx_email (email);

然后查看执行计划:

EXPLAIN SELECT * FROM users WHERE email LIKE 'alice%';

如果执行计划中typerange,说明走了索引。前缀匹配alice%可以走索引。

再看前导通配符:

EXPLAIN SELECT * FROM users WHERE email LIKE '%alice%';

此时执行计划中type大概率是ALL,也就是全表扫描。

5.2 为什么前导通配符会让索引失效

B+ 树索引是按字段值的从左到右顺序排列的。LIKE '%alice%'要求匹配任意位置出现的子串,索引无法定位起始点,只能逐行扫描。这是数据库管理系统索引结构的固有特性。

对比几种模式的索引使用情况:

模式是否能走索引原因
LIKE 'abc%'有固定前缀,索引可定位范围
LIKE '%abc'不能无固定前缀
LIKE '%abc%'不能无固定前缀,且中间匹配
LIKE 'abc_def%'前面部分固定,_不影响前缀定位
字段是函数表达式不能索引建立在原始字段上,函数包裹字段导致无法使用索引

5.3 慢 SQL 排查流程

LIKE查询变慢时,按以下顺序排查:

  1. 查看执行计划,确认是否全表扫描。
  2. 确认模式是否包含前导%
  3. 确认字段上是否建立了合适的索引。
  4. 确认数据量和返回行数,是否只需要部分字段。
  5. 使用EXPLAIN ANALYZEEXPLAIN EXTENDED查看实际扫描行数。

MySQL 8.0 可以使用:

EXPLAIN ANALYZE SELECT * FROM users WHERE email LIKE '%alice%';

5.4 索引失效的替代方案

如果必须做包含匹配,可以考虑以下方式:

  • 使用覆盖索引,配合INSTR函数。
  • 使用全文索引,效果更好。
  • 对经常需要模糊搜索的短文本字段,考虑引入 Elasticsearch。
  • 如果数据量可控,可以使用LOCATE('abc', email) > 0替代LIKE '%abc%',但本质上仍无法利用索引,只能减少部分解析开销。

INSTR示例:

SELECT * FROM users WHERE INSTR(email, 'alice') > 0;

功能上等于LIKE '%alice%',但语义更明确。注意它依然不能走索引。


6. LIKE 在接口 API 与批量任务中的应用

LIKE单独使用价值有限,在实际工程中通常出现在接口筛选条件、存储过程和批量数据处理任务里。这一节给出可以直接套用的示例。

6.1 接口查询参数拼接

在 Java、Python、Node.js 后端中,模糊查询条件通常是接口参数。直接拼接字符串是非常危险的做法,必须使用参数化查询或 ORM 框架的查询构造器。

Python 示例:

import pymysql conn = pymysql.connect( host="127.0.0.1", user="root", password="your_password", database="like_test", charset="utf8mb4" ) keyword = "alice" with conn.cursor() as cursor: sql = "SELECT id, name, email FROM users WHERE email LIKE %s" cursor.execute(sql, (f"%{keyword}%",)) rows = cursor.fetchall() for row in rows: print(row) conn.close()

注意,LIKE参数本身是%alice%,作为参数传给 SQL 语句,而不是拼进 SQL 字符串。这样即使keyword里包含%_,也只是字符串数据,不会改变 SQL 语义。

6.2 存储过程中的 LIKE 使用

存储过程常用于批量数据处理,LIKE可以结合游标逐行匹配。

MySQL 存储过程示例:

DELIMITER // CREATE PROCEDURE find_users_by_keyword( IN p_keyword VARCHAR(100) ) BEGIN SELECT id, name, email FROM users WHERE email LIKE CONCAT('%', p_keyword, '%') OR name LIKE CONCAT('%', p_keyword, '%'); END // DELIMITER ; CALL find_users_by_keyword('alice');

CONCAT('%', p_keyword, '%')在存储过程内部拼接模式字符串,不需要在调用端手动加百分号。

6.3 批量任务:按模式筛选并更新

假设要批量清洗数据,把所有remark包含 “VIP” 且邮箱为test.org的用户标记为“已通知”。

先确认筛选结果:

SELECT id, name, email, remark FROM users WHERE remark LIKE '%VIP%' AND email LIKE '%test.org';

确认无误后再执行更新:

UPDATE users SET remark = CONCAT(remark, ' [notified]') WHERE remark LIKE '%VIP%' AND email LIKE '%test.org';

批量任务执行前一定要先 SELECT 确认影响行数,再执行 UPDATE。

6.4 批量脚本与失败重试

在数据量较大时,建议使用脚本分批处理。Python 示例:

import pymysql import time conn = pymysql.connect( host="127.0.0.1", user="root", password="your_password", database="like_test", charset="utf8mb4" ) batch_size = 100 offset = 0 while True: with conn.cursor() as cursor: sql = """ SELECT id, name, email FROM users WHERE remark LIKE %s LIMIT %s OFFSET %s """ cursor.execute(sql, ("%VIP%", batch_size, offset)) rows = cursor.fetchall() if not rows: break for row in rows: # 在这里处理每一条记录 print(f"Processing id={row[0]}, name={row[1]}") offset += batch_size time.sleep(0.1) # 避免对数据库造成过大压力 conn.close()

分页处理时,OFFSET数据量大会变慢,更优方案是使用游标或基于主键的范围分页。批量任务应加上try-except和失败重试,避免一条异常导致整个任务中断。


7. LIKE 与 SQL 注入防护

LIKE关键字最容易出现安全问题的场景有两个:一是通配符没有转义导致 SQL 注入,二是拼接字符串导致注入点扩大。

7.1 注入风险

如果业务代码这样做:

# 危险写法,不要使用 keyword = request.args.get("keyword", "") sql = f"SELECT * FROM users WHERE name LIKE '%{keyword}%'"

攻击者传入%' OR 1=1 --之类的输入时,SQL 会被改写为:

SELECT * FROM users WHERE name LIKE '%%' OR 1=1 -- %'

最终结果是绕过查询条件,返回全表数据。这在数据库管理系统中属于高危漏洞。

7.2 防护方案

第一,使用参数化查询,这是最基础的处理方式。

第二,如果必须转义用户输入中的特殊字符,需要在拼接模式之前处理:

def escape_like(keyword: str) -> str: return keyword.replace("\\", "\\\\").replace("%", "\\%").replace("_", "\\_")

使用时:

safe_keyword = escape_like(keyword) sql = "SELECT * FROM users WHERE name LIKE %s ESCAPE '\\\\'" cursor.execute(sql, (f"%{safe_keyword}%",))

这样用户输入的%_会被视为普通字符,不会被当成通配符。

7.3 安全使用清单

  • 禁止字符串拼接 SQL。
  • 所有用户输入必须通过参数绑定传入。
  • 通配符必须按业务需求显式转义。
  • 测试LIKE查询时,至少测试包含%_、单引号、反斜杠的输入。
  • 数据库账号权限最小化,应用账号不应具备DROPTRUNCATE等高危权限。

8. LIKE 常见问题与排查方法

LIKE写法和查询并不复杂,但实际使用中经常遇到下面这些问题。

8.1 问题排查表

问题现象可能原因排查方式解决方案
中文搜索不到记录字符集或排序规则不一致检查表和字段的 character set统一为 utf8mb4,重建测试数据
大小写与预期不符排序规则为_ci(不区分大小写)查看 collation按需改用_binBINARY比较
%_被当成通配符没有转义检查模式字符串使用ESCAPE显式转义
查询很慢,全表扫描前导%导致索引失效使用EXPLAIN查看 type改为前缀匹配或引入全文索引
带空格的数据匹配不到字段包含前后空格使用CONCATTRIM检查清洗数据或使用TRIM(name)
NOT LIKE过滤掉 NULL 值SQL 三值逻辑检查字段是否允许 NULL补充OR field IS NULL
接口查询传入特殊字符报错未转义单引号或反斜杠查看数据库日志使用参数化查询
LIKE匹配表情符号失败字符集不支持检查字符集改为 utf8mb4

8.2 字符集问题

中文匹配不到,通常不是LIKE的问题,而是表或字段的字符集不是utf8mb4。检查方式:

SHOW CREATE TABLE users;

如果看到latin1gbk字符集,需要转字符集:

ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

执行前先备份数据。

8.3 空格问题

LIKE 'alice%'无法匹配alice(带尾部空格)。排查时可以先看长度:

SELECT id, name, LENGTH(name) FROM users WHERE id = 1;

如确认有空格,清洗数据:

UPDATE users SET name = TRIM(name) WHERE TRIM(name) <> name;

9. LIKE 最佳实践与使用建议

9.1 SQL 编写建议

  • 尽量使用前缀匹配。LIKE 'abc%'LIKE '%abc%'快很多,且可利用索引。
  • 必须用包含匹配时,控制扫描范围,加上其他过滤条件缩小数据量。
  • 模式字符串中如果包含用户输入,先转义%_\
  • NOT LIKE场景要警惕NULL值被过滤,按语义补条件。
  • 避免在LIKE前使用函数,例如WHERE LOWER(name) LIKE '%abc%'会导致索引失效。

9.2 索引设计建议

  • 高频前缀查询字段建议建立普通 B+ 树索引。
  • 不要只为了LIKE建立冗余索引,先分析是否真的高频。
  • 如果高频LIKE场景较多,考虑引入全文索引或外部搜索引擎。
  • 联合索引要使用左前缀规则,LIKE匹配字段放在联合索引靠后位置意义很小。

9.3 工程化建议

  • 保留一份最小可运行测试表结构和样例数据,方便新同事快速理解LIKE行为。
  • 批量任务必须加日志。每处理一批记录输出时间、处理行数、失败行数。
  • 批量任务要支持断点续跑。设计主键游标,不要单纯依赖OFFSET
  • 接口服务中,模糊查询参数要做长度限制和字符白名单。
  • 涉及人名的模糊搜索,建议结合排序规则明确大小写规则,避免业务反馈结果不稳定。

9.4 合规与授权提醒

  • 数据库中的个人信息查询,必须有合法的业务授权,不得越权查询他人数据。
  • 从公开网络搜索材料中截取的 SQL 示例,只用于本地学习,不用于生产环境。
  • 在正式环境执行UPDATEDELETE前,务必先在同结构测试库验证。
  • 发布或商用前,要对查询结果做人工复核,避免因LIKE通配符误匹配导致数据泄露。

10. 总结与下一步

LIKE的语法本身是 SQL 入门中最简单的一环,但工程中的LIKE远不止一个关键字那么简单。它牵扯出三个核心问题:能不能走索引、能不能防注入、能不能应对批量数据。

最值得深入验证的功能是前缀匹配的索引效果。建一张百万行测试表,分别用LIKE 'alice%'LIKE '%alice%'跑一遍EXPLAIN,实际观察typerange变成ALL,比死记硬背结论更有价值。

最容易踩的坑有两个:一是用户输入的通配符没有转义,导致LIKE变成万能匹配;二是在大表上用LIKE '%关键词%'做搜索,把数据库拖到全表扫描。这两个坑在面试题和实际故障中出现频率都很高,建议单独建立测试用例反复验证。

对于已经熟悉LIKE基本写法的读者,下一步可以尝试将LIKE查询改造成参数化接口,外加一个批量数据清洗脚本,跑通“传入关键字 -> 模糊匹配 -> 结果导出”的完整链路。这个链路在数据库管理系统类的日常开发任务中出现频率相当高。

如果你正在重温 SQL 基础,建议把这里提到的排序规则、索引失效、转义规则、注入防护四个知识点整理成自己的笔记。真正能区分新手和熟练开发者的,往往不是LIKE本身,而是这些围绕LIKE展开的边界情况。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询