2017-09-27 8 views
2

우리는 현저하게 성능/메모리 문제로 드러나는 객체 설계 문제를 다루는 것처럼 보입니다.복잡한 RavenDb 객체에서 지연로드

우리는 RavenDb 데이터베이스에 수천 개의 루트 집계 객체를 저장했습니다. 특정 대형 고객의 경우 이러한 개체가 너무 커서 웹 작업 (페이지 열기, 데이터 저장 등)을 효과적으로 수행 할 수 없게됩니다. 다음과 같이

구조는 다음과 같습니다 계정 개체가 그 아래의 집계 루트 이다, 작은 개체와 크기가 모두 "좋은"입니다 컬렉션의 과다가 매우 커질 수 있습니다 하나 개의 모음이라는 자료를 제외하고 루트 개체가 여러 메가 바이트 크기가되도록합니다. 이로 인해 계정에 대한 기본 CRUD 작업이 발생하고 내부 데이터가 매우 느리게 수행됩니다.

리소스 컬렉션의 개체는 거대하지 않지만 자체적으로 자식이 있으며 크기가 커집니다. 각 리소스 개체에는 메트릭, 작업, 경고, 크기 조정 및 "무거운"다른 컬렉션이 있습니다.

코드베이스는 수십만 줄의 코드가 포함 된 수퍼 콤플렉스입니다. 수백 줄의 코드하지 수천명의 자원 수집을 참조하고 자원이 그 안에 객체하지만, 각 자원 객체의 기본 자식 컬렉션에 대한 액세스가 빈번하고 대부분의 시간

질문에서 하나 개의 자원을 수행 할 것으로 보인다 검사하는 경우 : Account 객체, 그 밖의 모든 자식 및 객체, 그리고 첫 번째 수준의 Resource 객체 만로드 한 다음 리소스의 하위 하위 하위 노드를로드하는 방법은 무엇입니까? 모두

우리는 우리가 계정 개체를로드하려면 어떻게 데이터

+0

그래서 질문은 무엇인가? – Bestter

+0

"계정 개체, 기타 모든 자식 및 개체, 그리고 첫 번째 수준의 리소스 개체 만로드 한 다음 리소스의 하위 하위로드를 지연로드하는 방법 (지연로드 될 수있는 특정 컬렉션이 7 개 있습니다) " – Igorek

+0

@Igorek이 내 대답으로 문제를 해결 했습니까? –

답변

2

를로드/저장을 담당하는 하나의 저장소가 (- 게으른로드 할 수 있습니다 7 개 관련 모음 같이있다)의 기타 자식 및 객체, 그리고 첫 번째 수준의 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; } 
} 

(자원의 게으른로드 아이들), 당신은 자신의 문서로 그들을 .Store해야합니다 .

일단 이렇게하면 리소스를로드해도 모든 하위 개체가로드되지 않으므로 읽기 및 쓰기 작업시 성능이 향상됩니다.

하지만 그 아이들을로드해야 할 때는 어떻게해야합니까? 사용.포함 :

// 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); 
} 
0

우리가 어떻게 계정 개체를로드 할 그 기타 어린이 및 모든 개체 및 자원 객체의 첫 번째 수준 및 자료의 다음 게으른 부하 하위 아이들은? (느린로드가 가능한 컬렉션과 같은 것이 있습니다.)

OK, 내 다른 대답은 거대한 개체를 분해하는 데 권장되는 방법입니다. 단지 그것들을 그들 만의 독립적 인 대상으로 만드십시오.

그러나 당신이 말하기를 당신이 그들을 해산하기를 원하지 않는다고 말했기 때문에 이것을 할 수있는 또 다른 방법이 있습니다. 그것은 변압기를 사용하는 것입니다. 트랜스포머를 사용하면 Raven이 큰 Account 객체와 모든 자식을로드하는 것을 막을 수는 있지만 트랜스포머가 서버에서 실행되기 때문에 네트워크를 통해 거대한 객체를 웹 서버로 전송하지 않습니다.

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");