2011-08-13 73 views
30

8個月前在這裏討論了相同的主題:How do I speed up DbSet.Add()?。除了使用SqlBulkCopy,我們還沒有提出解決方案,這是我們不能接受的。我決定再次提出這個問題,希望圍繞這個問題可能會有新的想法和想法,並提出其他解決方法。至少我只是好奇爲什麼這個操作需要很長時間才能運行。爲什麼DbSet.Add的工作速度如此之慢?

嗯,問題是:我必須將30K實體更新到數據庫(EF 4.1,POCO)中。實體類型非常簡單,包含整數Id +其他4個整數屬性,與其他類型無關。 2例:

  • 他們都是新的記錄。運行context.Entities.Add(實體)爲每個實體需要90秒Cntx.Configuration.AutoDetectChangesEnabled = false(真正的值使它永遠運行)。然後SaveChanges只需要一秒鐘。另一種方法:將其連接到上下文這樣採用相同的90秒:

    Cntx.Entities.Attach(entity); 
    Cntx.Entry(entity).State = EntityState.Added; 
    
  • 有了一些變化全部是現有的記錄。在這種情況下它只需幾毫秒的時間將其附加到現有數據背景是這樣的:

    Cntx.Entities.Attach(entity); 
    Cntx.Entry(entity).State = EntityState.Modified; 
    

    看到區別?

Add方法的背後是什麼讓它工作如此慢得令人難以置信呢?

+0

把你的更新作爲一個答案,請。 –

+0

我嘗試了,但是我做不到,需要100個聲望點(9個以上)來自我回答。 – YMC

+1

Upvoted你的問題,現在你有101代表:) – Slauma

回答

27

我有有趣的性能測試結果,我發現了一個罪魁禍首。在我讀過的任何EF源文件中,我沒有看到任何類似的信息。

原來等於在基類中被覆蓋。基類應該包含在所有類型的具體實體之間共享的Id屬性。許多EF書籍推薦這種方法,並且非常瞭解。你可以在這裏找到它,例如:How to best implement Equals for custom types?

更確切地說,性能是由拆箱操作(對象到具體類型轉換),使其工作如此之慢而死亡。當我評論這行代碼時,它需要3秒才能反向運行到90秒!

public override bool Equals (object obj) 
{ 
    // This line of code made the code so slow 
    var entityBase = obj as EntityBase; 
    ... 
} 

正如我發現它,我開始考慮什麼可能是這個Equals的替代品。首先想到的是爲EntityBase實現IEquatable,但它並不是完全運行。所以我最終決定要爲我的模型中的每個具體實體類實現IEquatable。我只有其中的幾個,所以對我來說這只是一個小小的更新。您可以將整個Equal操作功能(通常是2個對象Ids比較)放入擴展方法中以在具體實體類之間共享,並像這樣運行它:Equal((EntityBase)ConcreteEntityClass)。最有趣的是,這個IEquatable加快了EntitySet.Add的6倍!

所以我沒有更多的性能問題,相同的代碼運行不到一秒鐘。 我得到了180倍的性能增益!驚人!

結論

  1. 最快速的方式來運行EntitySet.Add是有IEquatable用於特定實體(0.5秒)
  2. 缺少IEquatable使其運行持續3秒。
  3. 有等於(obj對象),其中大部分來源建議使它運行90秒
+2

@YMC:你能否詳細說明如何實現'IEquatable '?我對是否爲可變類型重寫object.Equals()感到困惑(因爲您也應該重寫object.GetHashCode(),但是如果哈希代碼在對象位於字典中時發生更改,它將變爲孤立)。在持久化對象之後,我可以使用數據庫中的主鍵,但在持久化之前,所有新對象的鍵都爲0.我將此作爲單獨問題提出,但未收到良好響應。 com/questions/9782235/implements-iequatable-for-poco –

+0

@YMC我也希望你詳細說明'IEquatable '的實現。我遇到了同樣的問題。 – vlad

+0

vlad和Eric,我現在還沒有訪問代碼,但我認爲你可以使用至少兩種方法:1)Guid生成主鍵值和GetHashCode()實現可能像'return Id一樣簡單。 GetHashCode()'2)如果是整數ID,它可能看起來像這樣:「IsNew? base.GetHashCode():Id.GetHashCode()',如果Id == 0,則IsNew返回true。糾正我,如果有任何錯誤的地方 – YMC

相關問題