2010-07-27 94 views
12

我目前正在爲我的web應用程序使用db4o存儲做一些研究。我很高興db4o是如何輕鬆工作的。因此,當我閱讀我喜歡的Code First方法時,因爲使用EF4 Code First的方式與使用db4o非常相似:創建您的域對象(PO​​CO's),將它們扔到db4o,並且永不回頭。爲什麼EF4 Code First在存儲對象時如此緩慢?

但是,當我做了一個性能比較,EF 4是非常緩慢。我無法弄清楚爲什麼。

我用下面的實體:

public class Recipe { private List _RecipePreparations; public int ID { get; set; } public String Name { get; set; } public String Description { get; set; } public List Tags { get; set; } public ICollection Preparations { get { return _RecipePreparations.AsReadOnly(); } }

public void AddPreparation(RecipePreparation preparation) 
    { 
     this._RecipePreparations.Add(preparation); 
    } 
} 

公共類RecipePreparation { 公共字符串名稱{;組; } public String Description {get;組; } public int評級{get;組; } public List Steps {get;組; } public List Tags {get;組; } public int ID {get;組; }}

爲了測試我新了一個配方的性能,並增加50.000 RecipePrepations。然後,我存儲對象db4o中像這樣:

IObjectContainer db = Db4oEmbedded.OpenFile(Db4oEmbedded.NewConfiguration(), @"RecipeDB.db4o"); 
db.Store(recipe1); 
db.Close(); 

這需要約13.000(MS)

我的東西與EF4存儲在SQL Server 2008(Express中,本地)是這樣的:

cookRecipes.Recipes.Add(recipe1); 
cookRecipes.SaveChanges(); 

而這需要200.000(MS)

現在如何在地球上是db4o的15(!!!)倍的速度是EF4/SQL?我是否錯過EF4的祕密渦輪按鈕?我甚至認爲db4o可以做得更快?由於我不初始化數據庫文件,我只是讓它動態增長。

+1

我的猜測是,正在執行許多單個插入語句的開銷是差異最大的部分。有沒有辦法指示EF4合併插入語句以減少開銷? – 2010-07-27 11:46:40

+0

@Lasse:是的,有。 EF實現了開箱即用的工作模式 - 請參閱我的答案。 – 2010-07-27 11:48:46

+1

我已經做了一些與Visual Studio分析。 cookRecipes.Recipes.Add(recipe1)約佔總時間的65%存儲,SaveChanges約爲35%(duh ...;))。 – Saab 2010-07-27 13:22:35

回答

3

你叫SaveChanges()裏面的循環?難怪它很慢!試着這樣做:

foreach(var recipe in The500000Recipes) 
{ 
    cookRecipes.Recipes.Add(recipe); 
} 
cookRecipes.SaveChanges(); 

EF希望你做出你希望所有的變化,然後調用SaveChanges一次。這樣,它可以優化數據庫通信和sql,以便在打開狀態和保存狀態之間執行更改,而忽略您已經撤消的所有更改。 (例如,添加50 000條記錄,然後刪除其中的一半,然後刪除一半,然後打到SaveChanges將只添加25000條記錄到數據庫中。)

+0

循環是在任何數據存儲在db4o或EF4/SQL之前。所以我首先新建食譜,然後在循環中添加RecipePreparations。 所以現在我有一個食譜,附加了50.000 RecipePreparation。 然後我將它存儲在db4o或EF4/SQL中。因此,db4o中的單個db.store(recipe1)和EF4中的cookRecipes.Recipes.Add(recipe1); cookRecipes.SaveChanges()。 – Saab 2010-07-27 11:53:32

+0

DB4O正在保存到本地機器上的文件嗎? EF4必須在本地打開數據庫連接。連接通常會保持開放,因此它是每次啓動一次的成本。嘗試添加一行以獲取數據庫中的第一個項目,然後在插入的時序循環中將連接時間從等式中排除。 – DamienG 2010-07-27 15:11:02

1

英孚擅長許多事情,但批量加載不是其中之一。如果你想要高性能的批量加載,直接通過數據庫服務器進行操作將會快於或任何 ORM。如果您的應用程序的唯一性能限制是批量加載,那麼您可能不應該使用EF。

+0

然後我對EF的使用有所懷疑。當你的應用程序依賴於一個非常複雜的模型(域對象),那麼我更喜歡一個數據庫(如db4o)。但是,當數據主要是表格時,您可以使用傳統的關係數據庫,並且可以使用像EF這樣的OR/M。但正如你所說,當你進行大量的批量加載/插入/更新時,EF失敗。 所以我害怕的其實是真的。在執行非常輕的數據庫操作時,EF4只是一個選項,並且您堅持使用關係數據庫。 – Saab 2010-07-27 13:34:54

+1

再說一次,不僅僅是EF,而且任何* ORM都會比DB服務器的批量加載功能慢。 EF可能比支持批量插入的ORM慢,但即使這些速度不如數據庫服務器專用批量加載功能上使用的流式API速度那麼快。批量加載對於大多數應用程序來說都是一個很好的例子,但如果它是你的麪包和黃油,那麼你最好使用SSIS之類的東西而不是ORM。 – 2010-07-27 13:40:56

+0

我同意大部分的OR/M都會比較慢,只是批量加載。但我不得不不同意OR/M也不能使用數據庫的批量加載功能。代碼很容易生成。 但我認爲EF4 Code First出了問題。由於將配方實體添加到dbContext需要很多時間(130秒)。存儲在數據庫中(dbContext.Recipes.SaveChanges)不是一個速度惡魔,對於50.001行,則爲70秒。換算成50.000/70 = 714行/秒。 – Saab 2010-07-27 13:53:22

1

只需添加其他答案:db4o通常運行進程中,而EF則提取進程外(SQL)數據庫。但是,db4o基本上是單線程的。因此,儘管對於一個請求來說這個例子可能會更快,但SQL將處理併發(多個查詢,多個用戶),比默認的db4o數據庫設置好得多。

相關問題