2013-02-09 68 views
4

我想學習如何使用RavenDB,併爲此創建了一個基本示例。 看起來初始化商店和查詢需要很長時間!如何優化用於檢索所有文檔的RavenDB查詢?

static void Main(string[] args) 
{ 
    const bool createNewEntities = true; 

    var sw = new Stopwatch(); 
    using(var store = new EmbeddableDocumentStore {DataDirectory = "~\\Data"}) 
    { 
     sw.Start(); 
     store.Initialize(); 
     sw.Stop(); 
     Console.WriteLine("Initialized in {0} ms.", sw.ElapsedMilliseconds); 

     if (createNewEntities) 
     { 
      sw.Reset(); 
      sw.Start(); 
      using(var session = store.OpenSession()) 
      { 
       sw.Stop(); 
       Console.WriteLine(); 
       Console.WriteLine("Opened session in {0} ms.", sw.ElapsedMilliseconds); 

       for(var i = 0; i < 10; i++) 
       { 
        var entity = new EntityA("Entity A " + DateTime.Now.ToLongTimeString()); 

        sw.Reset(); 
        sw.Start(); 
        session.Store(entity); 
        sw.Stop(); 

        if (i < 3) 
         Console.WriteLine("Stored '{0}' in {1} ms.", entity.Name, sw.ElapsedMilliseconds); 
       } 

       sw.Reset(); 
       sw.Start(); 
       session.SaveChanges(); 
       sw.Stop(); 
       Console.WriteLine("Saved changes in {0} ms.", sw.ElapsedMilliseconds); 
      } 
     } 


     sw.Reset(); 
     sw.Start(); 
     using(var session = store.OpenSession()) 
     { 
      sw.Stop(); 
      Console.WriteLine(); 
      Console.WriteLine("Opened EntityA session in {0} ms.", sw.ElapsedMilliseconds); 

      sw.Reset(); 
      sw.Start(); 
      var entities = session.Query<EntityA>().ToArray(); 
      sw.Stop(); 
      Console.WriteLine("Queried for all {0} EntityA in {1} ms.", entities.Length, sw.ElapsedMilliseconds); 
     } 


     sw.Reset(); 
     sw.Start(); 
     using(var session = store.OpenSession()) 
     { 
      sw.Stop(); 
      Console.WriteLine(); 
      Console.WriteLine("Opened EntityA session (again) in {0} ms.", sw.ElapsedMilliseconds); 

      sw.Reset(); 
      sw.Start(); 
      var entities2 = session.Query<EntityA>().ToArray(); 
      sw.Stop(); 
      Console.WriteLine("Queried (again) for all {0} EntityA in {1} ms.", entities2.Length, sw.ElapsedMilliseconds); 
     } 
    } 


    Console.WriteLine(); 
    Console.WriteLine(); 
    Console.WriteLine("Press ENTER to exit..."); 
    Console.ReadLine(); 
} 

這將產生以下輸出:

 
Initialized in 6132 ms. 

Opened session in 3 ms. 
Stored 'Entity A 08:50:14' in 129 ms. 
Stored 'Entity A 08:50:15' in 0 ms. 
Stored 'Entity A 08:50:15' in 0 ms. 
Saved changes in 29 ms. 

Opened EntityA session in 0 ms. 
Queried for all 10 EntityA in 463 ms. 

Opened EntityA session (again) in 0 ms. 
Queried (again) for all 10 EntityA in 1 ms. 

從該粗例如,我可以看出:

  • 初始化商店花費的時間量巨大!!
  • 存儲第一個實體(十個)需要相當長的一段時間。
  • 查詢所有實體首次需要很多時間,但第二次不需要任何時間。

如何正確查詢某個類型(EntityA)的所有文檔的數據庫? 當然,它不可能是RavenDB需要每個查詢的索引?特別是沒有任何標準的查詢?

(注:我打算使用嵌入在桌面應用程序,其中列出了所有文件,用於顯示數據庫中的內容DB)

+0

這樣的「爲什麼」這樣的問題的答案通常很難找到,難以應用(因此,「不具有建設性」)。不要問爲什麼它是這樣的,你可能想要編輯來問你需要在你的代碼中做什麼樣的事情來優化性能。 – 2013-02-09 08:08:07

+0

夠公平的。舉一個基本的例子,我的目的是作爲一個解釋性答案,比如「你使用錯了,因爲......」而不是簡單的是/否的答案,例如「是的,使用索引」,它不能解釋「爲什麼」。但你的觀點是合理的。我會嘗試重新說明我的問題! – Reyhn 2013-02-09 08:13:44

回答

4

這裏有三個延誤的原因:

初始化延遲
初始化文檔存儲確實是最昂貴的操作之一。由於您正在運行RavenDB的嵌入模式,因此它不僅必須建立與數據庫的連接,還必須啓動數據庫以及運行。在我的機器上(2.3Ghz i5筆記本電腦),初始化需要2516ms。

如果您正在運行完整的RavenDB服務器(不是嵌入式) - 大部分延遲都是在啓動服務器時。初始化客戶端將顯着加快。

這是合理的行爲,考慮到IDocumentStore(無論是嵌入式的還是普通的)是爲了保持單身。應用程序中應該只有一個實例,它應該在啓動時創建並在關閉時處理。

第一家店延遲
因爲你不提供自己的Id,烏鴉是自動生成使用其HiLo generation algorithm一個給你。這涉及從數據庫分配一個可分配的ID塊,這需要很少的時間。隨後的調用將會更快,因爲在塊被用完之前,他們不必擊中數據庫。

如果你提供你自己的財產Id,並用有效的標識符填充諸如entities/1entities/2等 - 那麼這將是更快,因爲你會跳過密鑰生成。

查詢延遲
第一次調用.Query<T>()當你不指定一個靜態指標將嘗試創建一個查詢表達式匹配的動態指標。即使獲得「所有」實體,情況也是如此,因爲它仍然必須使用元數據過濾實體類型。 RavenDB中的Collections是一個虛擬的東西,由元數據決定。這些文檔實際上是一起生活的 - 所以沒有其他方式可以獲取「集合」中的所有項目,而不是通過元數據進行查詢和過濾。

您看到的部分延遲是正在構建的動態索引。然後,這些項目將被編入索引。請注意,如果您添加了更多項目(比如說幾百項),那麼您仍然會得到相同的延遲,但是您不會收回所有項目。該索引自創建以來就是陳舊的了,而烏鴉只會返回其中的一小部分。在像你這樣的測試中,你可能想要明確地等待non-stale results。在實際應用中,您可能需要預先定義static index。事實上,您可以通過違反靜態索引來加快查詢速度。延遲將被移至索引創建時間而不是查詢時間。

如果你想避免使用索引可言,還有另一種方式:

session.Advanced.LoadStartingWith<EntityA>("EntityAs/"); 

這種方法不使用元數據過濾 - 它使用的鍵名本身。它直接與文檔存儲不匹配 - 因此速度更快。您將需要paginate以獲得大量結果 - 但無論如何,您仍然有同樣的疑慮。但是用這種方法,默認的頁面尺寸要小得多(25) - 所以你肯定會很快遇到這個問題。

我希望這能解答您的疑慮。如果您有其他人,請在評論中告訴我。

+0

非常好!這些答案正是我所希望的,還有更多!他們應該把你放在RavenDB文檔中! (: 謝謝!! – Reyhn 2013-02-10 08:18:13