C # Entity Framework 4 Свойства навигации, вызывающие низкую производительность при фиксации - PullRequest
9 голосов
/ 05 апреля 2011

Я прошу прощения за недостаток деталей в этом вопросе - первое, что мне нужно, чтобы помочь, это знать, где искать, чтобы найти больше деталей.

У меня проблема со свойствами навигации enity Framework 4, которые, очевидно, приводят к снижению производительности при фиксации изменений:

this.ObjectContext.SaveChanges();

Требуется более 30 секунд, когда одно из свойств навигации (таблица квитанций) содержит около 8000 строк (что не так много, поэтому должно быть в порядке).

Я использовал профилировщик SQL и вижу, что EF выдает * выбор из квитанций и что он очень медленный:

exec sp_executesql N'SELECT 
[Extent1].[Id] AS [Id], 
// full field list cut for brevity 
FROM [dbo].[Receipts] AS [Extent1]
WHERE [Extent1].[WarehouseId] = @EntityKeyValue1',
N'@EntityKeyValue1 int',@EntityKeyValue1=1

В настоящий момент я даже не вижу , почему необходимо выбрать все строки в этой таблице при вызове ObjectContext.SaveChanges ().

Нужно вставить 1 строку в эту таблицу, но это не объясняет, почему сначала выполняется выбор, и не объясняет, почему этот выбор занимает так много времени (тот же запрос занимает менее 1 секунды в диспетчере запросов. )

Итак, мой вопрос сейчас - я точно не знаю, в чем проблема - это:

  • Где / как я могу найти более подробную информацию о проблеме? Я не могу отладить в ObjectContext.SaveChanges (), поэтому я не знаю, что происходит внутри него.
  • Почему EF пытается выбрать * из квитанций?
  • Почему это так медленно? Точно такой же запрос скопирован + вставлен в менеджер запросов почти мгновенно

РЕДАКТИРОВАТЬ:

Я подтвердил, что это медленный код чека, комментируя вызов этого метода:

    private void AddReceipt(PurchaseInvoice invoice, 
                               PurchaseInvoiceLine invoiceLine)
    {
        if (invoice != null && invoiceLine != null)
        {
            Product product = invoiceLine.Product;
            if (product != null)
            {
                Receipt receipt = new Receipt{ foo = bar };
                WarehouseDetail detail = new WarehouseDetail{ foo = bar };
                receipt.WarehouseDetails.Add(detail);
                invoice.Receipts.Add(receipt);
            }
        }
    }

Но я все еще не понимаю, почему это заставляет EF выдавать этот запрос * select.

Я полагаю, что это может быть проблема с отложенной загрузкой, вызванная invoice.Receipts.Add(receipt). Потому что перед этой строкой invoice.Receipts пуст, и для того, чтобы .Add to Receipts, он должен сначала загрузить коллекцию. НО это не объясняет, почему он выбирается с помощью warehouseId = 1, когда его следует выбирать по invoiceId.

РЕДАКТИРОВАТЬ 2:

Я «исправил» проблему, заменив код EF в этом методе на прямые команды SQL. Это не очень хорошая идея - я не должен разбрасывать SQL, когда у меня есть совершенно хороший ORM. Но сейчас я все еще не понимаю, почему EF выполнял запрос select

    private void AddReceipt(PurchaseInvoice invoice, 
                               PurchaseInvoiceLine invoiceLine)
    {
        if (invoice != null && invoiceLine != null)
        {
            Product product = invoiceLine.Product;
            if (product != null)
            {
                Receipt receipt = new Receipt{ foo = bar };
                WarehouseDetail detail = new WarehouseDetail{ foo = bar };
                int id = SqlHelper.AddWarehouseDetail(detail);
                receipt.WarehouseDetailId = id;
                SqlHelper.AddReceipt(receipt);
            }
        }
    }

Ответы [ 3 ]

1 голос
/ 13 мая 2011

Вы выдаете с помощью «Свойства навигации» на вашем объекте «Склад». Удалите это свойство навигации. Связь все еще будет сохраняться, но она не будет запрашивать все поступления с этим складом при создании объекта поступления. У меня была та же проблема, и это решило мою проблему.

1 голос
/ 05 апреля 2011

Поскольку это вставка, она обновляет ваш объект, выбирая значение обратно и повторно заполняя объект.Теперь позвольте мне ответить на ваши вопросы, которые вы изложили:

  1. Вам не нужно отлаживать вместо SaveChanges(), что, по вашему мнению, в любом случае не имеет большого смысла.

  2. Это на самом деле не select * from Receipts.Это делает select * from Receipts where WarehouseId = 1.Так что по некоторым причинам вы возражаете против того, чтобы получить все квитанции для склада с идентификатором 1.

  3. Это может зависеть от многих вещей, которые вы действительно не можете получить сейчас,Но для начала нужно проверить скорость пинга между блоком вашего приложения и блоком БД.Также проверьте, что RAM не заполнена на поле БД.Вот где я бы начал, и это обычная проблема для того, что вы описываете.

Хорошим инструментом для отладки EF является EF Profiler.http://efprof.com Это поможет вам гораздо больше, чем профилировщик SQL.

0 голосов
/ 13 мая 2011

У вас включена отложенная загрузка?Если это так, он будет запускать запросы для таблиц WarehouseDetails и Receipts при доступе к соответствующим свойствам навигации.Я всегда гарантирую, что отложенная загрузка отключена, чтобы я не запускал запросы непреднамеренно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...