Spring Data MongoDB中@DocumentReference(lazy=true)是否存在N+1问题及延迟加载请求排查方法
问题解答
1. 实际产生的数据库请求次数
你的代码执行过程中,总共会产生2次数据库请求:
- 第一次:
parentRepo.findAll()触发的查询,获取所有Parent文档,对应你当前看到的那条日志。 - 第二次:当你调用
parents.get(0).getChildren()时,因为children是懒加载的代理集合,Spring Data MongoDB会批量发起一次请求,根据当前Parent中存储的所有ChildID,一次性从child集合中查询出所有关联的子文档,而非逐个Child发起请求。
2. 是否存在N+1问题
这里不会出现传统意义上的N+1查询问题:
- 传统N+1是指查询N个父文档后,每个父文档单独触发一次子查询,总共产生
1+N次请求。 - 而Spring Data MongoDB的
@DocumentReference(lazy = true)对于集合类型的关联,会在首次访问时批量查询所有关联子文档,所以对于单个Parent的子集合,只会额外产生1次请求,而非与子文档数量等同的N次请求。
不过要注意:如果后续你遍历多个Parent并分别访问它们的children集合,那么每个Parent都会触发一次独立的批量子查询,此时会产生1 + M次请求(M是你访问的Parent数量)。这种场景下可以考虑使用急切加载(去掉lazy = true)或者自定义查询通过$lookup手动关联,来避免多次请求。
3. 如何配置日志查看所有数据库请求
你当前的日志配置只打印了MongoTemplate的部分请求,懒加载触发的子查询日志需要调整日志级别来覆盖:
在你的配置文件中添加或修改以下日志配置:
# 打印MongoTemplate的所有操作(包括懒加载触发的查询) logging.level.org.springframework.data.mongodb.core.MongoTemplate=DEBUG # 打印DbRef解析过程的详细日志,包含懒加载的触发逻辑 logging.level.org.springframework.data.mongodb.core.convert.DefaultDbRefResolver=DEBUG
这样就能看到懒加载时触发的批量查询日志了,类似这样的条目:
find using query: { "_id" : { "$in" : [ObjectId("xxx"), ObjectId("yyy")] } } fields: Document{{}} for class: class com.test.Child in collection: child
内容的提问来源于stack exchange,提问作者Zakhar
相关产品推荐
相关产品推荐

