[英]Lazy loading in complex RavenDb objects
看起來我們正在處理一個深思熟慮的對象設計問題,現在它正在表現為重大的性能/內存問題。
我們在 RavenDb 數據庫中存儲了數千個根聚合對象。 對於某些大客戶,這些對象變得太大而無法有效執行 Web 操作(打開頁面、保存數據等)。
結構如下: Account 對象是聚合根 在它下面,有許多較小的對象和集合,它們的大小都“很好”,除了一個稱為 Resources 的集合,它可以增長得非常大,並可能導致根對象大小為數兆字節。 這會導致 Account 及其內部數據的基本 CRUD 操作執行速度非常慢
Resource 集合中的對象本身並不大,但它們有自己的子對象,並且會向上拖動大小。 每個 Resource 對象都有 Metrics、Actions、Alerts、Scaling 和其他“重”集合
我們的代碼庫非常復雜,有數十萬行代碼; 數百甚至數千行代碼引用 Resource 集合並檢查其中的 Resource 對象,但對每個 Resource 對象的底層子集合的訪問似乎很少見,並且一次只完成一個資源
問題:我們如何加載 Account 對象、其所有雜項子對象和對象,以及僅第一級 Resource 對象,然后延遲加載Resources 的子子對象? (有 7 個可以延遲加載的特定集合)
我們有一個負責加載/保存數據的存儲庫
我們如何加載 Account 對象、其所有雜項子對象和對象,以及僅第一級 Resource 對象,然后延遲加載 Resources 的子子對象? (有 7 個可以延遲加載的特定集合)
使用 Raven 進行按需加載非常簡單。 要做到這一點,讓你的資源擁有你想要延遲加載的東西作為它們自己的文檔,然后在父級上擁有一組 ID。
前:
class Resource
{
public List<Foo> Foos { get; set; }
public List<Bar> Bars { get; set; }
// ... etc
}
后:
class Resource
{
// These are the things we need to lazy load.
public List<string> FooIds { get; set; }
public List<string> BarIds { get; set; }
}
至於您的 Foo 和 Bar 對象(Resource 的延遲加載的子對象),您需要將它們存儲為它們自己的文檔。
一旦你這樣做了,加載一個 Resource 就不會加載它的所有子對象,讓你在讀寫時獲得性能提升。
但是當你需要加載那些孩子的時候呢? 使用 .Include:
// Query for Resource and include the children in a single remote call.
var resourcesWithChildren = docSession
.Query<Resource>()
.Include(r => r.FooIds) // Include the related Foos
.Include(r => r.BarIds) // Include the related Bars
.Where(...)
.ToList();
foreach (var resource in resourcesWithChildren)
{
// Grab the children; they're already loaded, so this won't induce a remote call.
var foos = docSession.Load<Foo>(resource.FooIds);
var bars = docSession.Load<Bar>(resource.BarIds);
}
我們如何加載 Account 對象、其所有雜項子對象和對象,以及僅第一級 Resource 對象,然后延遲加載 Resources 的子子對象? (有 7 個可以延遲加載的特定集合)
好的,我的另一個答案是分解巨大物體的推薦方法; 只是讓它們成為自己的獨立對象。
但是,既然你說你不想做分解它們的工作,那么還有另一種方法可以做到這一點,那就是使用變壓器。 使用轉換器不會使 Raven 免於加載大的 Account 對象及其所有子對象,但由於轉換器是在服務器上執行的,它不會通過網絡將大對象發送到您的 Web 服務器。
public class AccountWithFirstLevelResourcesTransformer : AbstractTransformerCreationTask<Account>
{
public AccountWithFirstLevelResourcesTransformer()
{
TransformResults = accs => from acc in accs
select new Account
{
...
Resources = acc.Resources.Select(fullResource => new Resource
{
// Only the properties we want loaded here.
Name = fullResource.Name,
...
})
...
};
}
}
您將在啟動期間安裝此轉換器:
new AccountWithFirstLevelResourcesTransformer().Execute(RavenStore); // RavenStore is your IDocumentStore singleton.
然后您的 .Load 調用將如下所示:
// This account will have only the first level resources.
var account = dbSession.Load<AccountWithFirstLevelResourcesTransformer, Account>("accounts/1");
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.