2017-05-01 89 views
1

我正在使用Microsoft SQL Server和實體框架。我有N個(例如10000個)項目可以插入。在插入每個項目之前,我需要插入或更新現有組。由於性能低下而無法正常工作。這是因爲我產生了太多的查詢。每次在循環中,我正在通過查詢Groups表(由三個索引)參數來查找組。從另一個表更新行的實體框架批量插入

我在考慮首先使用WHERE IN查詢(Groups.Where(g => owners.Contains(g.OwnerId) && ..)查詢所有組,但是我記得這樣的查詢受限於參數數量。

也許我應該寫一個存儲過程?

這是我的示例代碼。我使用IUnitOfWork圖案包裹的EF DbContext

public async Task InsertAsync(IItem item) 
{ 
    var existingGroup = await this.unitOfWork.Groups.GetByAsync(item.OwnerId, item.Type, item.TypeId); 

    if (existingGroup == null) 
    { 
     existingGroup = this.unitOfWork.Groups.CreateNew(); 
     existingGroup.State = GroupState.New; 
     existingGroup.Type = item.Code; 
     existingGroup.TypeId = item.TypeId; 
     existingGroup.OwnerId = item.OwnerId; 
     existingGroup.UpdatedAt = item.CreatedAt; 

     this.unitOfWork.Groups.Insert(existingGroup); 
    } 
    else 
    { 
     existingGroup.UpdatedAt = item.CreatedAt; 
     existingGroup.State = GroupState.New; 

     this.unitOfWork.Groups.Update(existingGroup); 
    } 

    this.unitOfWork.Items.Insert(item); 
} 

foreach(var item in items) 
{ 
    InsertAsync(item); 
} 

await this.unitOfWork.SaveChangesAsync(); 

回答

1

有提高性能的三要素時,批量插入:

  • 設置AutoDetectChangesEnabledValidateOnSaveEnabled爲false:

_db.Configuration.AutoDetectChangesEnabled = false; _db.Configuration.ValidateOnSaveEnabled = false;

  • 將你的插入分成幾部分,使用相同的DbContext,然後重新創建它。段的大小應該從用例到用例有多大,我在重新創建上下文之前在大約100個元素上取得了最佳性能。這是由於觀察了DbContext中的元素。 也請確保不要爲每個插入重新創建上下文。 (見Slauma的答案在這裏Fastest Way of Inserting in Entity Framework

  • 當檢查其他表,確保使用IQueryable在可能的情況,並只在必要時與ToList()FirstOrDefault()工作。由於ToList()FirstOrDefault()加載對象。 (看到這裏What's the difference between IQueryable and IEnumerableRichard Szalay的答案)

像你描述的這些技巧幫了我最當批量插入的場景。還有其他的可能性。例如SP's和BulkInsert函數。

+1

我用你的建議禁用AutoDetectChanges幾個查詢。不幸的是,EF產生了太多沉重的查詢,並且我還重寫了很少的EF查詢以處理原始SQL查詢和存儲過程。現在工作正常。 – Rakoo

+0

很高興聽到這個消息。那麼在某些情況下,最好這樣做。有時候EF過於複雜,但我們必須注意,我們自己不這樣做。 –

相關問題