簡體   English   中英

為什么DBSet.Find越來越慢?

[英]Why is DBSet.Find getting slower and slower?

我正在桌面應用程序中使用實體框架訪問mysql數據庫。 數據庫安裝在同一個系統上,我是現在唯一使用它的人。

我有一個方法可以檢查來自某個集合docs對象是否已經存在於數據庫中,如果不是,它們將被添加到數據庫中,最后將執行DBContext上的save方法。 該方法在我的程序中循環執行多次。

我注意到,每次執行該方法時,查找速度都會變得越來越慢,即使要查找的對象數量相當穩定(每次大約500次)。 可能是什么原因?

代碼看起來或多或少像這樣:

TimeSpan timeToFind = new TimeSpan();

foreach (var docFromResult in docs)
{
    DateTime operationStart = DateTime.Now;
    var existingDocument =
       db.VaStDocuments.Find(docFromResult.Id, docFromResult.OwnerId, docFromResult.Year);
    timeToFind += DateTime.Now - operationStart;
    if (existingDocument != null && docFromResult.Hash.Equals(existingDocument.Hash))
    {
        continue;
    }
    if (existingDocument == null)
    {
        db.VaStDocuments.Add(docFromResult);
    }
    else if (!docFromResult.Hash.Equals(existingDocument.Hash))
    {
        existingDocument.Hash = docFromResult.Hash;
        existingDocument.IsNew = true;
        existingDocument.Text = null;
    }
    docsForNotification.Add(docFromResult);
}
if (docsForNotification.Any())
{
  db.SaveChangesDisplayValidationErrors();
}

因此,在數據庫中找不到該文檔是非常罕見的情況,所以基本上這里唯一的數據庫活動是Find方法。
timetoFind 通常隨着方法的每次執行而增加。 在可能20-30次循環之后,可能以0.5-2s開始達到120s。

您的DbContext會跟蹤您檢索的項目以及您對這些檢索項目所做的更改。

這樣可以添加/更新/刪除這些項目,而無需為每個操作與數據庫通信。 僅在調用SaveChanges時,才會將更改與數據庫通信。

這使您可以在將這些更改提交到數據庫之前使用新添加或更改的對象。

考慮一對多關系船舶客戶 - 訂單:客戶有零個或多個訂單,每個訂單只屬於一個客戶。

現在您可以先介紹一個新客戶。 之后您可以介紹訂單,而客戶還沒有ID:

using (var dbContext = new MyDbContext(...))
{   // Introduce a Customer:
    Customer customerToAdd = GetCustomerData();
    var addedCustomer = dbContext.Customers.Add(customerToAdd);

    // Introduce an order for this Customer
    Order addedOrder = dbContext.Orders.Add(new Order()
    {
        // addedCustomer has no Id yet, we can't use addedCustomer.Id
        Order.Customer = addedCustomer;
        ...
    });
    dbContext.SaveChanges();
}

由於DbContext會跟蹤添加的客戶,因此您可以在保存更改之前使用它。

它還允許您在不添加Customer First的情況下添加訂單:

var notAddedCustomer = new Customer() {...}
var order1= dbContext.Orders.Add(new Order()
{
    // this order belongs to a new customer that has not been added yet:
    Customer = notAddedCustomer
}

dbContext檢測到尚未添加客戶,並將自行添加。 如果您為同一個notAddedCustomer創建另一個訂單,則dbContext必須能夠檢測到在引入第一個訂單期間添加了此客戶。

此外,如果刪除客戶並嘗試向他提供新訂單,則dbContext需要檢測到此客戶已被刪除,並且無法添加新訂單。 同樣,如果在添加一些訂單后刪除客戶,dbContext應檢測到這一點。

這就是dbContext需要跟蹤更改的原因。 如果你有很多改變的對象,這會減慢使用速度。 dbContext的大多數用戶只允許在相當短的時間內進行相對少量的更改。

如果您在執行SaveChanges之前需要進行大量更改,並且確定在執行實際的SaveChanges之前不需要檢測任何更改,則可以使用Queryable.AsNoTracking關閉跟蹤。 這大大提高了查詢和添加項目的速度。 缺點是在使用相關對象時必須使用ID而不是對象。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM