标准答案
- 先通过 SQL 日志和链路追踪确认是否存在一次列表请求触发 N 次相似关联查询。
- 一对一或多对一且关联字段有限时,JOIN 或批量预加载通常合适。
- 一对多关联若直接 JOIN 可能让主记录倍增,应根据页面需要做批量查询后在应用层组装,或只取必要摘要。
- 预加载要按实际页面字段选择,不能为避免 N+1 一次拉取所有嵌套关系。
- 对于图形化或多 resolver 场景,可以用请求级 DataLoader 合并同类 Key 查询,避免重复访问。
题目解析
N+1 在开发数据量小时往往不明显:十条记录只是十一条 SQL,到了每页一百条、多个关联字段和高并发时,数据库连接、网络往返和锁竞争都会被放大。
解决 N+1 不是简单把所有关联改成 eager loading。过度预加载会把不需要的宽表、历史记录和大对象带进内存,反而增加一次请求的时间和峰值内存。
常见误区
- 关闭懒加载后不分析页面依赖,改成一次性加载整个对象图。
- 用 JOIN 获取一对多详情后没有去重或聚合,列表项数量和统计结果被放大。