← [ BACK_TO_NOTES ]

ORM 的 Eager Loading 与 Lazy Loading

区分 ORM 关联数据的 eager 与 lazy 获取时机,并说明它们与 API response shape、conditional include、batch loading 和 N+1 的关系。

#synthesis #growing #backend #database

[!info] related notes

ORM 的 Eager Loading 与 Lazy Loading

范围

这篇讨论 ORM 获取“关联数据”的时机,不讨论前端代码分包意义上的 Lazy Loading。

核心区别

Eager Loading
→ 查询主体时已经知道需要关联数据,一起预取

Lazy Loading
→ 先取主体,真正访问关联时再发查询

例如:

User + Assessments 一开始就需要
→ eager / preload / include

先查 User,某个分支后来才需要 Teams
→ lazy getTeams()

API Response Shape 不是同一个维度

GET /users/1?include=favorites

这是 API 层决定“这次响应要什么”。后端看到参数后,可以立刻构造带关联的查询,这仍然属于 conditional eager loading。

因此:

API 是否返回关联数据
≠
ORM 是 eager 还是 lazy

Eager 的适用场景

  • API contract 明确总是需要该关联;
  • 批量列表中需要同一种关联数据;
  • 希望避免逐对象访问导致 N+1。

Eager 不一定意味着“必须一条巨大 JOIN”。ORM 也可能用少量批量查询实现预取。

Lazy 的适用场景

  • 关联只在少数业务分支中需要;
  • 是否需要关联要根据刚查出的主体状态才能决定;
  • 关联数据昂贵,而且绝大多数请求不会访问。

最大风险:N+1

const users = await findUsers()
for (const user of users) {
  await user.getAssessments()
}

可能变成:

1 次 users 查询
+ N 次 assessments 查询

Lazy 本身不是错误;问题是把逐对象 lazy access 用在批量结果上,却没有预取或批处理。

实用决策规则

  1. 先由 API / use case 决定这次需要什么数据;
  2. 再由数据访问层选择 JOIN、preload、batch query 或 lazy query;
  3. 不要把“返回字段可配置”误认为“应该默认 lazy”;
  4. 看 ORM 代码时始终追问:最终会发几次 SQL?
创建于 2026/9/14 更新于 2026/9/14
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本