昨天有位朋友在留言里提到:模糊查询。这确实是项目里高频、又特别容易写出性能坑的地方。
很多开发者写模糊查询,上来就:
SELECT * FROM user WHERE name LIKE '%张三%'
本地数据少跑得飞快,一上线数据量一大,直接慢查询、接口卡死。
今天这篇,就把PHP + MySQL 模糊查询讲透:怎么写、怎么优化、怎么避免全表扫描,全部是生产可用实战。
一、先搞懂:
LIKE 的三种写法差别巨大
1. 前后都加 %(最慢,不推荐)
WHERE name LIKE '%张三%'
无法命中索引,全表扫描,数据量大必慢
2.右边加 %(可以走索引,推荐)
WHERE name LIKE '张三%'
能命中普通索引,速度快很多,适合前缀搜索
3. 左边加 %(也很慢)
WHERE name LIKE '%张三'
同样无法走索引实际业务很少这么用一句话记住:% 放前面 = 索引失效,% 放后面 = 索引有效。
二、PHP 实际开发怎么写?(防注入版)永远不要直接拼接变量,必须用预处理。正确示例(PDO)
// 搜索关键词 $keyword = $_GET['keyword'] ?? ''; // 安全处理,只右模糊 $like = $keyword . '%'; // SQL预处理 $sql = "SELECT id,name,phone FROM user WHERE name LIKE ? LIMIT 20"; $stmt = $pdo->prepare($sql); $stmt->execute([$like]); $list = $stmt->fetchAll(PDO::FETCH_ASSOC); // 统一接口返回 apiResponse(0, 'success', $list);
如果你必须要左右模糊可以用,但一定要加 LIMIT,否则必崩:
$like = '%' . $keyword . '%'; $sql = "SELECT id,name FROM user WHERE name LIKE ? LIMIT 20";
小经验:生产环境,单页返回绝不超过 50 条,不然不仅慢,还会给前端渲染压力。
三、生产环境优化方案(进阶)
方案 1:给字段加普通索引
ALTER TABLE user ADD INDEX idx_name(name);
然后只用右模糊,速度提升非常明显。
方案 2:使用全文索引 FULLTEXT(大数据量推荐)
ALTER TABLE user ADD FULLTEXT ft_name(name);
查询语句改成:
SELECT * FROM user WHERE MATCH(name) AGAINST(? IN BOOLEAN MODE)
优点:速度远快 LIKE支持分词搜索适合文章、商品、用户列表方案
3:关键字段单独存,避免大表模糊查比如搜索手机号、姓名,不要在一张超级大的日志表里直接模糊查,可以建一张小表专门用于搜索。
四、接口里必须加的两道 “保险”
1. 限制关键词长度防止用户输入超长字符串拖慢查询:
$keyword = trim($keyword);
if (mb_strlen($keyword) > 20) {
apiResponse(400, '搜索关键词过长,请精简');
}2. 空关键词不查
if (empty($keyword)) {
apiResponse(0, '请输入搜索关键词', []);
}3. 必须加
LIMITLIMIT 20
这是后端最后的底线。
五、一个真实踩坑案例
之前帮人排查一个接口:
1.表数据 120w+
2.模糊查询%关键词%
3.没加 LIMIT结果:
4.查询耗时 3.8 秒
并发一高直接把数据库 CPU 打满
优化后:
1.加全文索引
2.改用 MATCH AGAINST加 LIMIT 20 耗时直接降到30 毫秒以内。
六、总结
1.能用右模糊,就不用左右模糊
2.永远用预处理,防 SQL 注入
3.大数据量优先全文索引,而不是 LIKE
4.任何模糊查询都要加 LIMIT
5.关键词长度
必须限制做到这 5 点,你的模糊查询基本不会出线上问题。
感谢昨天留言提醒 “模糊查询” 的朋友,问题非常实用。后续大家在开发中遇到什么高频痛点,都可以在评论区留言,我会专门写文章详细拆解。
持续分享 PHP 生产环境实战干货。































18605917465
客服QQ