Массовые вставки Entity Framework, вызывающие проблему выбора n + 1 - PullRequest
1 голос
/ 09 июля 2011

Я вставляю несколько экземпляров определенного объекта в базу данных, используя Entity Framework. У меня есть один объектный контекст, к которому я присоединяю несколько объектов «Продукт». Вставляемый мной объект не имеет отношения к какой-либо другой таблице в базе данных. Это чисто отдельная сущность. Я использую инструмент EFProf для профилирования приложения.

Когда я вызываю «SaveChanges ()» для сохранения своих сущностей «Продукт» на SQL Server, EFProf предупреждает меня, что у меня есть антишаблон «Выбрать N + 1». Я не понимаю, как это возможно, потому что я просто вставляю. Мое понимание «Выбрать N + 1» заключается в том, что это относится к неэффективному поиску объектов. Я ничего не получаю, только вставляю.

Когда я проверяю сгенерированный SQL, я вижу, что Entity Framework сгенерировал от моего имени оператор select, который возвращает Id вновь вставленного объекта. Этот оператор выбора выполняется для каждой сущности, которую я вставляю. Может ли это быть причиной проблемы выбора N + 1? Если так, как я могу избежать этого анти-паттерна при вставке нескольких сущностей одного типа в один вызов SaveChanges ()?

Сгенерированный SQL ниже:

insert [dbo].[Products]
  ([ProductName],
   [ProductNum],
   [Price],
   [EntryDate],
   [Description],
   [Category],
   [UnitsInStock])
values('TestProduct' /* @0 */,
   0 /* @1 */,
   0 /* @2 */,
   '2011-07-09T17:14:49.00' /* @3 */,
   'Category: Test Products - Name TestProduct' /* @4 */,
   'Test Products' /* @5 */,
   0 /* @6 */)


select [Id]
from   [dbo].[Products]
where  @@ROWCOUNT > 0
       and [Id] = scope_identity()

Ответы [ 3 ]

1 голос
/ 09 июля 2011

Вы не можете избежать этого дополнительного выбора.Когда вы используете автоматически сгенерированные идентификаторы в базе данных и ваша модель правильно настроена для них, EF всегда создаст этот дополнительный выбор.

Вам не нужно беспокоиться.Производительность «массовой вставки» с EF настолько ужасна, что этот дополнительный выбор при каждой вставке ничего не значит.То, с чем вам следует иметь дело, - это сама обработка, потому что EF создаст отдельную обратную передачу в базу данных для каждой вставленной записи, и в этом проблема.Если вы действительно хотите передать большое количество объектов в базу данных, вы хотите делать это часто (это не разовая работа), и вы ожидаете некоторой производительности, вам определенно следует искать другое не-EF решение.Например, уже упоминалось SqlBulkCopy.

Если вам просто нужно вставить несколько экземпляров в какую-то операцию, просто оставьте это.Так работает EF.

0 голосов
/ 09 июля 2011

Если вы пытаетесь выполнить массовую вставку, мне кажется, что SCOPE_IDENTITY() бесполезен, поскольку он хранит единственное скалярное значение, а не диапазон.Я предам свое незнание EF, но преобразует ли он этот код в BULK INSERT команду, или SQLBulkCopy, или что-то еще?

Если вы собираетесь делать одну вставку за раз,затем сначала проверяется @@ROWCOUNT вместо того, чтобы вставлять выражение where, что выглядит лучше в целом:

IF @@ROWCOUNT = 1
BEGIN
    SELECT [Id]
        FROM [dbo].[Products]
        WHERE [Id] = SCOPE_IDENTITY();
END

Или вообще не надоедать, поскольку, если следующий набор результатов пуст, вы теперь знаете, что@@ROWCOUNT было:

SELECT [Id]
    FROM [dbo].[Products]
    WHERE [Id] = SCOPE_IDENTITY();
0 голосов
/ 09 июля 2011

Нет прямой поддержки массовых вставок с использованием Entity Framework.Однако вы можете настроить его на использование SQLBulkCopy . Эта статья MSDN является хорошим примером.

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