知识卡片

波动加载陷阱:延迟加载集合的性能反噬

普通读书笔记卡

内容

延迟加载本身是为了减少不必要的数据库访问,但用得不小心反而会造出更多访问——这种反噬被称为”波动加载”。典型场景:给一个集合用了延迟加载,然后代码逐个访问这个集合里的元素——如果每访问一个元素就单独触发一次数据库读取,结果就是本该一次读完的数据被拆成了逐个访问的多次数据库调用,作者亲眼见过这种模式明显拖累应用性能。避免这个问题的办法是转换延迟加载的粒度:不要让集合内部的元素各自延迟加载,而是让”这整个集合”作为一个整体去延迟加载——一旦触发加载,就把集合里的全部内容一次性读完,这样访问集合时无论是逐个取元素还是整体遍历,都只对应一次数据库调用。这个策略在集合规模巨大时会受限(比如要处理全世界所有IP地址这种量级),不过对象模型里通常不会通过普通关联把这么庞大的数据集直接串起来,真遇到这种巨型集合场景,需要专门的值列表处理器来应对。可迁移启发:给一个容器(集合、列表、分页结果)加”按需加载”策略时,要想清楚延迟粒度到底该落在”容器整体”还是”容器里的每个元素”——粒度选错了,看似省流量的优化反而会把一次批量操作拆解成大量零散的小操作,造成比不做优化还差的结果。

参考来源

- 位置:《企业应用架构模式》第二部分"模式"之"第11章 对象-关系行为模式"之"11.3.1 运作机制"(源文件:_epub-src/OEBPS/Text/000098.html) - 结论依据:原文说明"延迟加载的另一个风险是它容易导致产生超出需要的数据库访问。这种波动加载一个很好的例子是,如果用延迟加载填充一个集合,然后每次只访问其中的一个元素。这会使每读取一个对象都要访问一次数据库……一种避免这个问题的方法是不使用延迟加载的集合,而使类集合本身成为延迟加载,加载类集合的时候,一次加载所有的内容",直接支撑本卡结论。 - 原始内容:我发现波动加载会影响应用程序的性能。一种避免这个问题的方法是不使用延迟加载的集合,而使类集合本身成为延迟加载,加载类集合的时候,一次加载所有的内容。