Django学习笔记

`prefetch_related(...)` **不是** 传统意义上的"连表查询(JOIN)",而是一种 **通过额外的独立查询来预加载关联数据** 的机制。它和 `select_related()` 才是 Django 中实现"连表"效果的两个关键方法,但二者原理完全不同。


✅ 简单对比

| 方法 | 适用关系 | 实现方式 | 是否真正"连表(JOIN)" | 适用场景 |

|------|--------|--------|------------------|--------|

| `select_related()` | **一对一(OneToOne)、外键(ForeignKey)** | 使用 **SQL JOIN**,一次查询获取主表+关联表字段 | ✅ 是 | 关联对象少、层级浅(如 `task.project.owner`) |

| `prefetch_related()` | **一对多(OneToMany)、多对多(ManyToMany)**、反向 ForeignKey | **先查主表,再用 IN 查询关联表**,通常 2 次或更多查询 | ❌ 否(是"分步查",不是 JOIN) | 加载集合(如 `task.annotations`、`user.groups`) |


�� 以你的代码为例:

```python

queryset.prefetch_related(

'annotations', # Task → Annotation(一对多)

'annotations__completed_by' # Annotation → User(外键)

)

```

Django 实际执行的查询类似:

  1. **查询 Task**:

```sql

SELECT * FROM tasks WHERE id IN (1, 2, 3, ...);

```

  1. **查询这些 Task 的所有 Annotation**:

```sql

SELECT * FROM annotations WHERE task_id IN (1, 2, 3, ...);

```

  1. **查询这些 Annotation 的 completed_by 用户**:

```sql

SELECT * FROM users WHERE id IN (101, 102, 103, ...);

```

然后 Django 在 **Python 内存中** 把这些数据"组装"起来,使得你访问 `task.annotations.all()` 时无需再查数据库。

> ✅ 优点:避免了在循环中触发 N+1 查询(比如 100 个任务,每个任务查一次 annotations → 101 次查询,变成 2~3 次)

> ❌ 缺点:不能用 SQL JOIN 一次性完成,对超大数据集可能内存压力大


❓ 那什么时候用 JOIN(`select_related`)?

如果你要查 **单个外键对象**,比如:

```python

Task.objects.select_related('project', 'project__organization')

```

Django 会生成:

```sql

SELECT ...

FROM tasks

JOIN projects ON tasks.project_id = projects.id

JOIN organizations ON projects.organization_id = organizations.id;

```

→ 一次查询搞定,适合"一对一"或"单值外键"。


�� 总结回答你的问题:

> **`prefetch_related(...)` 不是连表查询(JOIN),而是一种"分步预加载"机制。**

> 它专门用于高效加载 **一对多、多对多** 的关联数据集合,**避免 N+1 查询问题**,

> 而真正的"连表"在 Django 中是由 `select_related()` 实现的。

所以,你可以理解为:

  • **`select_related` = SQL JOIN(适合单对象)**

  • **`prefetch_related` = 先查主表,再批量查关联表(适合列表/集合)**

两者常常配合使用,以达到最佳性能。

相关推荐
这个DBA有点耶6 小时前
NULL不是空——数据库里最反直觉的设计,90%新人踩过的坑
数据库·mysql·代码规范
这个DBA有点耶8 小时前
AI写的SQL跑崩了生产库,这锅谁背?
数据库·人工智能·程序员
镜舟科技8 小时前
Databricks 再提 LTAP,AI 时代的数据底座为何重回大一统叙事?
数据库·架构·agent
Databend9 小时前
从湖仓升级为 Agent 时代的数据控制面,Snowflake 和 Databricks 有哪些布局
大数据·数据库·agent
ClouGence13 小时前
SQL Server CDC 能放到 Always On 备库读吗?一文讲透原理与实践
数据库·sql server
先吃饱再说1 天前
存储的进化:从 MySQL 到浏览器缓存,数据到底住在哪?
数据库
Nturmoils1 天前
字段太多看不全,ksql 的展开模式和输出控制怎么用
数据库·后端
Databend1 天前
Agent 轨迹分析与归因的数据工程实践
大数据·数据库·agent
这个DBA有点耶1 天前
SQL改写进阶:标量子查询的“隐形代价”与消除实战
数据库·mysql·架构
smallyoung1 天前
数据库乐观锁深度解析:MySQL、PostgreSQL 实战 + Spring Boot 集成指南
数据库·mysql·postgresql