加载中...

N+1 查询问题是使用 ORM(对象关系映射)时的经典性能反模式:先用 1 条查询取出 N 条主记录,随后在遍历中访问每条记录的关联对象,触发懒加载,对每条记录再发 1 条 SQL,总计 1+N 条查询。
根源是 ORM 的懒加载(Lazy Loading)默认策略与面向对象的遍历写法相结合:代码上只是访问属性,底层却是一次次数据库往返。单条查询都很快,问题隐蔽,列表越长放大越严重,数据库连接与网络往返成为瓶颈。
通用思路是把 N 次关联查询合并:一是预加载/急加载(Eager Loading),如 Hibernate/JPA 的 JOIN FETCH 与 EntityGraph、Rails 的 includes、Django 的 select_related(连接)与 prefetch_related(IN 批量);二是用一条 JOIN 查询直接取平铺结果;三是 DataLoader 模式(GraphQL 生态常用),把同一批次的关联键收集后合并为一次 IN 查询并缓存。
可通过 SQL 日志观察重复模板语句、APM 工具的调用统计,或在测试中断言查询次数来发现。该问题也是"ORM 需要理解其生成 SQL"这一原则的最常见例证。

登录 后参与讨论
暂无讨论,来发表第一条评论吧