2014-11-14 49 views
3

這可能是更多的一般性NOSQL基礎結構問題。事件存儲使用nosql性能注意事項

通過事件採購系統,我將事件文檔保存爲ravendb。

在我的領域模型有多種類型的事件,低於基本的例子:

public abstract class Event 
{ 
    public Guid AggregateId { get; set; } 

    public Event(Guid aggregateId) 
    { 
     AggregateId = aggregateId; 
    } 
} 

public class NewPersonEvent : Event 
{ 
    public string Name { get; set; } 

    public NewPersonEvent(Guid id, string name) : Base(id) 
    { 
     Name = name; 
    } 
} 

public class NewOrderEvent : Event 
{ 
    public DateTime OrderDate { get; set; } 
    public double OrderCost { get; set;} 


    public NewOrderEvent(Guid id, DateTime date, double cost) : Base(id) 
    { 
     OrderDate = date; 
     OrderCost = cost; 
    } 
} 

事件被持久化作爲事件的文件,無論該事件是由什麼類型的總和。

這是在ravendb中爲所有事件使用一種文檔類型的最佳方法。或者是否有任何好處,將每個聚合的文檔類型分組

而不是僅具有「事件」文檔,而是具有「PersonEvent」文檔和「OrderEvent」文檔。

這兩種方法各有什麼優缺點,具體是否存在性能問題?

+0

附註。儘可能使用'DateTimeOffset'而不是'DateTime'。請參閱http://stackoverflow.com/a/14268167/3638742 – fgauna 2015-02-11 22:58:52

回答

1

你對事件覆蓋默認標籤名稱...

docStore.Conventions.FindTypeTagName = type => typeof(Event).IsAssignableFrom(type) ? DocumentConvention.DefaultTypeTagName(typeof(Event)) : DocumentConvention.DefaultTypeTagName(type); 

然後,每當你Event做一個查詢它只是工作,並檢索所有事件。 session.Query<Event>()

如果是這樣,你可以拍攝自己的腳,因爲如果你只是想事件的一個子集,你這樣做session.Query<NewPersonEvent>()這是怎麼回事,因爲你推翻在開始的標籤約定檢索所有事件。 你仍然可以用另一種方式來做,但它不會那麼直截了當(例如,枚舉事件類型和枚舉過濾器)。

我會投票不覆蓋默認的RavenDB行爲,將不同的事件類型留作自己的文檔集合,並且只使用多圖索引。

Raven docs指出,靜態索引優於動態索引,因此它不應該成爲性能問題。 docs

如果您不想混淆標記約定,但可以爲事件的子集創建更多索引,創建map/reduce索引以聚合每個事件類型的計數等等。

該索引將是一個多地圖索引,您可以選擇兩種風格。

選項1

public class Events_All : AbstractMultiMapIndexCreationTask 
    { 
     public Events_All() 
     { 
      AddMap<NewPersonEvent>(newPersonEvents => 
       from newPersonEvent in newPersonEvents 
       select new 
       { 
        Id = newPersonEvent.AggregateId 
       }); 

      AddMap<NewOrderEvent>(newOrderEvents => 
       from newOrderEvent in newOrderEvents 
       select new 
       { 
        Id = newOrderEvent.AggregateId 
       }); 
     } 

    } 

選項2(反射)

public class Events_All2 : AbstractMultiMapIndexCreationTask 
{ 
    public Events_All2() 
    { 
     AddMapForAll<Event>(events => 
      from @event in events 
      select new 
      { 
       Id = @event.AggregateId 
      }); 
    } 
} 

以下是使用RavenDB.Tests.HelpersShouldly的NuGet包的示例測試。它使用第一個示例索引,但您可以修改它以使用第二個索引。

public class MultimapIndexTest : RavenTestBase 
    { 
     private readonly Random _random = new Random(); 

     [Fact] 
     public void GetAll_HasBoth_Success() 
     { 
      //Arrange 
      const string personName = "Jimmy"; 
      double randomCost = _random.Next(); 

      var event1 = new NewPersonEvent(Guid.NewGuid(), personName); 
      var event2 = new NewOrderEvent(Guid.NewGuid(), DateTime.Now, randomCost); 

      using (var docStore = NewDocumentStore()) 
      { 
       docStore.ExecuteIndex(new Events_All()); 

       using (var sesion = docStore.OpenSession()) 
       { 
        sesion.Store(event1); 
        sesion.Store(event2); 
        sesion.SaveChanges(); 
       } 

       docStore.WaitForStaleIndexesToComplete(); 

       //Act 
       var events = GetAll(docStore).ToList(); 

       //Assert 
       events.ShouldNotBeEmpty(); 
       events.Count().ShouldBe(2); 

       var newPersonEvent = events.FirstOrDefault(x => x is NewPersonEvent) as NewPersonEvent; 
       newPersonEvent.ShouldNotBe(null); 
       newPersonEvent.Name.ShouldBe(personName); 

       var newOrderEvent = events.FirstOrDefault(x => x is NewOrderEvent) as NewOrderEvent; 
       newOrderEvent.ShouldNotBe(null); 
       newOrderEvent.OrderCost.ShouldBe(randomCost); 
      } 
     } 

     private IEnumerable<Event> GetAll(DocumentStore docStore) 
     { 
      using (var session = docStore.OpenSession()) 
      { 
       return session.Query<Event, Events_All>(); 
      } 
     } 
    }