资讯动态

MybatisPlus模糊查询性能优化:当`like`遇上多值匹配,如何避免全表扫描?

发布时间:2026/9/14 3:59:00 来源:尧图企业网站定制
MybatisPlus模糊查询性能优化多字段匹配的深度实践在数据驱动的现代应用中模糊查询几乎是每个系统都无法绕开的功能需求。当数据量达到百万级甚至更高时一个简单的LIKE %keyword%操作就可能成为系统性能的阿喀琉斯之踵。特别是当业务需求要求在多个字段上进行模糊匹配时问题会变得更加复杂——索引失效、全表扫描、执行计划劣化等问题接踵而至。1. 多字段模糊查询的性能陷阱1.1 OR条件与索引失效MybatisPlus中常见的多字段模糊查询写法是这样的QueryWrapperUser queryWrapper new QueryWrapper(); queryWrapper.like(username, 张) .or() .like(email, example) .or() .like(phone, 138);这种链式OR操作生成的SQL类似于SELECT * FROM user WHERE username LIKE %张% OR email LIKE %example% OR phone LIKE %138%问题核心在于前导通配符%导致索引失效OR条件使得优化器难以选择最优执行计划多字段组合查询时数据库可能选择全表扫描1.2 执行计划分析对比我们通过EXPLAIN分析不同写法的执行计划差异查询类型索引使用情况扫描行数执行时间单字段右模糊使用索引1,20015ms多字段OR模糊全表扫描1,000,0001,200ms多字段UNION ALL部分使用索引3,60045ms提示在MySQL中LIKE value%可以使用索引但LIKE %value%会导致索引失效2. 优化策略与实践方案2.1 查询结构调整策略一UNION ALL替代OR// 方案1分别查询后合并结果 ListUser result new ArrayList(); result.addAll(userMapper.selectList(new QueryWrapperUser().like(username, 张))); result.addAll(userMapper.selectList(new QueryWrapperUser().like(email, example))); result.addAll(userMapper.selectList(new QueryWrapperUser().like(phone, 138))); // 方案2使用UNION ALL SQL Select(SELECT * FROM user WHERE username LIKE %${keyword}% UNION ALL SELECT * FROM user WHERE email LIKE %${keyword}% UNION ALL SELECT * FROM user WHERE phone LIKE %${keyword}%) ListUser searchByMultipleFields(Param(keyword) String keyword);策略二条件预筛选// 先通过精确匹配缩小范围 ListInteger userIds userMapper.selectObjs( new QueryWrapperUser() .select(id) .eq(status, 1) .between(create_time, startDate, endDate) ).stream().map(o - (Integer)o).collect(Collectors.toList()); // 再在缩小后的范围内做模糊查询 if(!userIds.isEmpty()) { queryWrapper.in(id, userIds) .and(wrapper - wrapper .like(username, 张) .or() .like(email, example)); }2.2 MybatisPlus 3.x特性应用Lambda表达式条件构造// 更安全的类型安全写法 ListUser users userMapper.selectList(Wrappers.UserlambdaQuery() .and(qw - { for(String keyword : keywords) { qw.or().like(User::getUsername, keyword) .or().like(User::getEmail, keyword); } }) .eq(User::getIsDeleted, 0));条件构造器优化技巧// 动态条件构建 QueryWrapperUser queryWrapper new QueryWrapper(); boolean hasCondition false; if(StringUtils.isNotBlank(username)) { queryWrapper.like(rightLike(username), username); hasCondition true; } if(StringUtils.isNotBlank(email)) { if(hasCondition) queryWrapper.or(); queryWrapper.like(rightLike(email), email); hasCondition true; } // 辅助方法避免前导通配符 private String rightLike(String value) { return value.endsWith(%) ? value : value %; }3. 高级优化方案3.1 引入全文索引对于频繁的模糊查询场景考虑使用专业搜索技术-- MySQL全文索引 ALTER TABLE user ADD FULLTEXT INDEX ft_search (username, email, phone); -- 使用MATCH AGAINST语法 SELECT * FROM user WHERE MATCH(username, email, phone) AGAINST(张 example IN BOOLEAN MODE);MybatisPlus中集成Select(SELECT * FROM user WHERE MATCH(username, email, phone) AGAINST(#{query} IN BOOLEAN MODE)) ListUser fullTextSearch(Param(query) String query);3.2 异步查询与缓存策略实现方案用户发起搜索请求系统立即返回空结果查询ID后台异步执行复杂查询结果缓存到Redis并通知前端前端通过WebSocket或轮询获取结果// 伪代码示例 public SearchResult searchAsync(SearchParams params) { String searchId UUID.randomUUID().toString(); // 放入消息队列异步处理 mqTemplate.send(search.queue, new SearchTask(searchId, params)); // 立即返回 return new SearchResult(searchId, Collections.emptyList()); } // 消费者处理 public void handleSearchTask(SearchTask task) { ListUser results complexSearch(task.getParams()); redisTemplate.opsForValue().set(search:task.getSearchId(), results); notifyClient(task.getSearchId()); }4. 实战案例电商用户搜索优化某电商平台用户表(2000万数据)的多字段搜索优化实践原始方案queryWrapper.like(nickname, keyword) .or().like(mobile, keyword) .or().like(email, keyword);平均响应时间3.2秒CPU使用率峰值90%优化方案建立(nickname, mobile, email)的组合索引使用UNION ALL拆分查询增加结果缓存if(isComplexSearch(keyword)) { // 复杂查询走异步流程 return searchAsync(keyword); } else { // 简单查询使用优化后的UNION方案 return fastSearch(keyword); }优化后指标平均响应时间480msCPU使用率峰值35%99线延迟1秒配置参考# MybatisPlus配置 mybatis-plus.global-config.db-config.logic-not-delete-value0 mybatis-plus.global-config.db-config.logic-delete-value1 # 连接池配置 spring.datasource.hikari.maximum-pool-size20 spring.datasource.hikari.connection-timeout30000在具体实现时我们发现当查询条件超过3个OR组合时使用UNION ALL方案性能优势更加明显。但对于小数据量表(10万行以下)简单的OR查询可能更合适需要根据实际业务场景进行权衡。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价