2011-05-09 25 views
75

基本上,我一個事務中插入35000個對象:與ObjectContext相比,爲什麼在EF 4.1中插入實體很慢?

using(var uow = new MyContext()){ 
    for(int i = 1; i < 35000; i++) { 
    var o = new MyObject()...; 
    uow.MySet.Add(o); 
    } 
    uow.SaveChanges(); 
} 

這永遠需要! 如果我使用底層ObjectContex噸(通過使用IObjectAdapter),它仍然很慢,但需要大約20秒。它看起來像DbSet<>正在做一些線性搜索,這需要平方米的時間...

任何其他人看到這個問題?已經拉吉斯拉夫在評論表示

+3

不知何故,我相信答案將類似於此:http://stackoverflow.com/questions/5917478/what-c​​auses-attach要慢慢進入ef4/5921259#5921259 – 2011-05-09 22:55:44

回答

119

正如,你需要禁用自動變化檢測,以提高性能:

context.Configuration.AutoDetectChangesEnabled = false; 

這種變化檢測是默認DbContext API中啓用。

爲什麼DbContext的行爲與ObjectContext API如此不同的原因是,當啓用自動變化探測DbContext API的更多功能將調用DetectChanges內部比ObjectContext API的功能。

Here您可以在默認情況下找到那些調用DetectChanges的函數列表。它們是:

  • AddAttach,在DbSet
  • FindLocal,或者Remove成員GetValidationErrorsEntry,或SaveChangesDbContext
  • Entries方法成員DbChangeTracker

特別是Add請致電DetectChanges,這對您經歷的糟糕表現負責。

我只是在SaveChanges中自動對比ObjectContext API調用DetectChanges,而不是AddObject以及上面提到的其他相應方法。這就是爲什麼默認性能ObjectContext更快。

爲什麼他們在DbContext中引入這種默認的自動變化檢測功能?我不確定,但似乎禁用它並在適當的位置手動調用DetectChanges被認爲是advanced and can easily introduce subtle bugs into your application so use [it] with care

+0

@Ladislav:你是對的我沒有找到這個,因爲我只是在尋找插入問題:-( – Hartmut 2011-05-10 07:26:23

+0

感謝您的解釋,我實際上是調用上下文.Configuration.AutoDetectChangesEnabled = false,但是我在Seed()方法的數據庫構建過程中完成了它,我認爲這會設置默認值,我沒有意識到我必須爲每個實例調用它。謝謝! – Hartmut 2011-05-10 07:29:04

+3

@Hartmut:你可以在派生的DbContext的構造函數中禁用變化檢測,然後你總是禁用它。但個人不知何故,這種關於「可能引入微妙的錯誤」的說法在禁用時會讓我感到緊張。我默認情況下會更改檢測,並且只有在您的代碼塊中將其禁用時,性能提升很明顯,並且我認爲它不會導致問題的安全。 – Slauma 2011-05-10 09:16:54

9

EF 4經驗不多。3 CodeFirst:

移除1000分的對象與AutoDetectChanges =真:23秒

移除1000分的對象與AutoDetectChanges =假:11秒

插入1000個對象與AutoDetectChanges =真:21秒

插入的使用AutoDetectChanges = false的1000個對象:13秒

+1

謝謝Zax。根據這個問題,你的結果是35,000個?你會發現,在原始問題中,它表明性能會以二次方式下降 – 2012-03-19 09:45:06

0

除了您在此處找到的答案之外。知道在數據庫級別插入比添加更多的工作是很重要的。數據庫必須擴展/分配新空間。然後它必須至少更新主鍵索引。雖然索引在更新時也可能會更新,但它並不常見。如果有外鍵需要讀取這些索引以確保參照完整性得以維持。觸發器也可以發揮作用,儘管這些可以以同樣的方式影響更新。

所有數據庫工作在由用戶條目產生的每日插入活動中都有意義。但是,如果您只是上傳現有的數據庫,或者有一個生成大量插入的進程。你可能想看看加快速度的方法,推遲到最後。通常在插入時禁用索引是常用的方法。根據具體情況可以完成非常複雜的優化,它們可能有點壓倒性。

只要知道一般情況下插入將花費比更新更長的時間。

2

在.netcore 2.0這個被移到:

context.ChangeTracker.AutoDetectChangesEnabled = false;