本文目录导读:

在Java开发中,避免全表扫描的核心思路是让数据库查询尽量使用索引,而不是在内存中处理大量数据,下面从设计层面、代码层面和数据库层面给出具体案例和解决方案。
核心原则:让查询走索引
全表扫描通常发生在:
- 查询条件没有索引
- 查询条件使用了函数或计算
- 使用了
LIKE '%keyword'模糊查询 - 隐式类型转换
- 数据量很小(MySQL 可能直接全表扫描)
具体案例与解决方案
案例1:模糊查询导致全表扫描
❌ 错误写法
String sql = "SELECT * FROM user WHERE name LIKE '%" + keyword + "%'";
✅ 解决方案
- 使用前缀匹配(走索引):
String sql = "SELECT * FROM user WHERE name LIKE '" + keyword + "%'";
- 或使用全文索引(MySQL):
ALTER TABLE user ADD FULLTEXT INDEX idx_name (name); SELECT * FROM user WHERE MATCH(name) AGAINST('keyword');
案例2:隐式类型转换
❌ 错误写法
String sql = "SELECT * FROM user WHERE phone = " + phone; // phone是varchar,phone是String
👉 phone 是 VARCHAR 类型,但传入的是数字,MySQL 会转成数字比较,导致索引失效。
✅ 正确写法
String sql = "SELECT * FROM user WHERE phone = '" + phone + "'";
👉 或者使用 PreparedStatement:
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user WHERE phone = ?");
ps.setString(1, phone);
案例3:在索引列上使用函数
❌ 错误写法
String sql = "SELECT * FROM order WHERE DATE(create_time) = '2024-01-01'";
✅ 正确写法
String sql = "SELECT * FROM order WHERE create_time >= '2024-01-01 00:00:00' AND create_time < '2024-01-02 00:00:00'";
案例4:分页查询深度偏移
❌ 错误写法
String sql = "SELECT * FROM user LIMIT 100000, 10";
👉 先扫描10万行,再取最后10行。
✅ 优化方案
-
延迟关联:先查主键,再关联查数据
String sql = "SELECT u.* FROM user u " + "INNER JOIN (SELECT id FROM user ORDER BY id LIMIT 100000, 10) tmp " + "ON u.id = tmp.id"; -
游标分页:记录上一次查询的最后id
String sql = "SELECT * FROM user WHERE id > ? ORDER BY id LIMIT 10";
案例5:用 Java Stream 代替 SQL 过滤
❌ 错误写法
List<User> allUsers = userRepository.findAll(); // 全表扫描
List<User> activeUsers = allUsers.stream()
.filter(u -> "ACTIVE".equals(u.getStatus()))
.collect(Collectors.toList());
✅ 正确写法
List<User> activeUsers = userRepository.findByStatus("ACTIVE"); // 走索引
案例6:批量操作使用 IN 替代多个 OR
❌ 错误写法
String sql = "SELECT * FROM user WHERE id = 1 OR id = 2 OR id = 3";
✅ 正确写法
String sql = "SELECT * FROM user WHERE id IN (1, 2, 3)";
👉 IN 在 MySQL 中会使用 range 扫描,性能远优于 OR。
Java 代码层面的通用优化模板
使用 PreparedStatement + 绑定变量
// 避免SQL注入 + 减少SQL解析次数 + 让数据库使用缓存执行计划 String sql = "SELECT * FROM user WHERE name = ? AND age > ?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setString(1, "张三"); ps.setInt(2, 20); ResultSet rs = ps.executeQuery();
使用 ORM 框架时要小心
- MyBatis:
- 避免在
<if>标签中拼接OR 1=1 - 用
<bind>或CONCAT控制模糊查询前缀
- 避免在
- JPA/Hibernate:
- 注意
@Query中的 HQL 是否有隐式类型转换 - 用
Specification+CriteriaBuilder避免全表
- 注意
数据量大时使用游标或流式查询
// JPA 流式查询(避免一次性加载全部数据到内存) @QueryHints(@QueryHint(name = "org.hibernate.fetchSize", value = "1000")) Stream<User> streamAllUsers();
避免全表扫描的检查清单
| 场景 | 错误做法 | 正确做法 |
|---|---|---|
| 模糊查询 | LIKE '%keyword%' |
LIKE 'keyword%' 或全文索引 |
| 隐式类型转换 | WHERE phone = 123 |
WHERE phone = '123' |
| 函数使用 | WHERE DATE(col)=... |
WHERE col BETWEEN ... |
| 分页深偏移 | LIMIT 100000,10 |
游标/延迟关联 |
| 代码过滤 | 查询全部后Java过滤 | SQL条件过滤 |
| 多个OR | OR 连接 |
IN (...) |
| 无索引查询 | 频繁查询无索引字段 | 加索引 |
一句话总结:
Java 中避免全表扫描,最有效的方法不是优化代码,而是让 SQL 走索引——包括明确 SQL 执行计划、检查索引覆盖、避免破坏索引的函数/计算/类型转换。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播