当前位置: 首页 > ds >正文

对比N+1查询和关联聚合查询

通常我们管第一种模式叫 “N+1 查询”,第二种叫 “关联聚合查询”。下面从几个角度来比较,帮助你做出选择。


1. 性能与资源消耗

方案SQL 语句数网络往返次数数据库负载Java 处理
N+1 查询
(先查项目,再遍历项目查设备状态数)
1 + N 条1 + N 次多次小查询需要在代码中汇总各个查询结果
关联聚合查询
(一次 SQL → 按项目+状态分组计数)
1 条1 次单次大查询(GROUP BY)直接拿到全量结果,按项目和状态映射到 DTO
  • N+1 查询在项目数量(N)大的时候,网络往返和数据库连接开销会急剧上升,容易成为性能瓶颈。
  • 关联聚合查询只需要一次往返,数据库做完 GROUP BY 聚合后,Java 端几乎不用额外计算,通常响应更快、更稳定。

2. 可维护性与拓展性

  • N+1 查询

    • 逻辑散落在多条 SQL/DAO 调用里,代码量和耦合度都更高。
    • 如果新增状态或需要统计别的维度(如按设备类型、品牌等),要修改多处查询逻辑。
  • 关联聚合查询

    • 聚合逻辑集中在一条 SQL 里,可读性更好。
    • 新增统计维度(例如按设备类型再分组)也只需在同一句 SQL 加 CASE WHEN 或多维度 GROUP BY

3. 示例

假设表结构简化为:

-- 项目表
CREATE TABLE project (project_id   BIGINT PRIMARY KEY,project_name VARCHAR(100)
);-- 设备表
CREATE TABLE device (device_id    BIGINT PRIMARY KEY,project_id   BIGINT,state        VARCHAR(20)  -- 如 '待调试', '待验收' 等
);

2.1 关联聚合查询示例

SELECTp.project_id,p.project_name,-- 按不同状态计数SUM(CASE WHEN d.state = '待调试' THEN 1 ELSE 0 END) AS cnt_debugging,SUM(CASE WHEN d.state = '待验收' THEN 1 ELSE 0 END) AS cnt_acceptance,SUM(CASE WHEN d.state = '已上线' THEN 1 ELSE 0 END) AS cnt_online
FROM project p
LEFT JOIN device dON p.project_id = d.project_id
GROUP BY p.project_id, p.project_name;
  • 优点
    • 一条 SQL 就拿到所有项目在各状态下的设备数。
    • 如果新增“维修中”“已淘汰”之类的状态,只要再加一个 SUM(CASE…)

2.2 Java 端映射(MyBatis / Spring Data JPA)

// DTO 接口或类
public class ProjectDeviceStat {private Long projectId;private String projectName;private Integer cntDebugging;private Integer cntAcceptance;private Integer cntOnline;// getters & setters
}// MyBatis mapper
@Select("""SELECTp.project_id AS projectId,p.project_name AS projectName,SUM(CASE WHEN d.state = '待调试' THEN 1 ELSE 0 END) AS cntDebugging,SUM(CASE WHEN d.state = '待验收' THEN 1 ELSE 0 END) AS cntAcceptance,SUM(CASE WHEN d.state = '已上线' THEN 1 ELSE 0 END) AS cntOnlineFROM project pLEFT JOIN device d ON p.project_id = d.project_idGROUP BY p.project_id, p.project_name""")
List<ProjectDeviceStat> selectProjectDeviceStats();

4. 何时考虑 N+1 查询?

  • 当项目数量非常 (比如只有 1–3 个)且业务逻辑简单时,用第一种写法可能更直观,且对性能影响可忽略不计。
  • 但一旦项目量或状态维度增加,性能损耗就会成倍增加,不推荐用于生产环境。

5. 结论

  • 推荐: 使用 关联聚合查询(单表 JOIN + GROUP BY),既减少网络和数据库往返,又让统计逻辑集中、易于扩展和维护。
  • 仅当项目量极少、统计字段极少,且对性能无严格要求时,才可酌情使用第一种 N+1 查询。

希望对你有所帮助!如果需要进一步优化(如添加索引、使用视图或物化视图、或在 Java 层面缓存),可以再详细讨论。

http://www.xdnf.cn/news/2785.html

相关文章:

  • Spring Cloud Config 自定义配置源与动态刷新:从原理到企业级实践
  • Kafka 配置参数性能调优建议
  • 31、简要描述Promise.all的用途
  • 在 Ubuntu 22.04 x64 系统安装/卸载 1Panel 面板
  • 电子电器架构 ---电气/电子架构将在塑造未来出行方面发挥啥作用?
  • [Linux运维] [Ubuntu/Debian]在Lightsail Ubuntu服务器上安装Python环境的完整指南
  • 在线图书管理系统的结构化设计过程讲解
  • [密码学实战]SDF之设备管理类函数(一)
  • uniapp常用
  • case和字符串操作
  • 网络原理 - 10(HTTP/HTTPS - 1)
  • UniApp 实现分享功能
  • 深入探究C++ 中的stack、queue和deque
  • 图论---拓扑排序(DFS)
  • delphi使用sqlite3
  • 《AI大模型应知应会100篇》第39篇:多模态大模型应用:文本、图像和音频的协同处理
  • 基于 Python 的实现:居民用电量数据分析与可视化
  • C++入门(namespace/输入输出)
  • 2025A卷-正整数到Excel编号之间的转换
  • 对Electron打包的exe文件进行反解析
  • 在idea开发中遇到的20个bug
  • 晶振PCB设计核心要点与规范
  • 设备指纹护航电商和金融反欺诈体系建设
  • 飞凌嵌入式T527核心板获得【OpenHarmony生态产品兼容性证书】
  • STL标准模板库
  • 杰理-ios获取不了时间问题
  • 爬虫过程中如何确保数据准确性
  • Qt/C++面试【速通笔记四】—Qt中的MVC模式
  • VLM-E2E:通过多模态驾驶员注意融合增强端到端自动驾驶——论文阅读
  • RecoNIC 入门:SmartNIC 上支持 RDMA 的计算卸载-FPGA-智能网卡-AMD-Xilinx