#postgresql #entity-framework-core #npgsql
Вопрос:
Я работаю с минимальным API .NET Core 6 с базой данных PostgreSQL 13. Пакеты, которые я использую Microsoft.EntityFrameworkCore
, 6.0.0 и Npgsql.EntityFrameworkCore.PostgreSQL
. У меня есть настройки LogLevel.Information
, чтобы я мог просматривать запросы SQL, создаваемые ядром Entity Framework, по мере его взаимодействия с базой данных.
Я замечаю, что, когда я вставляю записи через свою конечную точку, она выполняет серию отдельных операторов вставки вместо ожидаемого (VALUES (<row1 values>),(<row2 values>))
формата. Например, это ведение журнала:
INSERT INTO <mytable> (<columns>) VALUES (<row1 values>);
INSERT INTO <mytable> (<columns>) VALUES (<row2 values>);
Это мой код для вставки:
context.Items.AddRange(list);
await context.SaveChangesAsync();
Есть ли способ объединить все значения в один INSERT
запрос?
Ответ №1:
@святослав-данилов ответ не точен.
EF Core пакует все вставки/обновления: при выполнении сохранений в DbContext все накопленные изменения отправляются с помощью одной команды в один оборот (для этого можно использовать средство поиска пакетов, такое как wireshark).
Обратите внимание, что в некоторых ситуациях это может быть эффективнее, чем один запрос ВСТАВКИ, так как инструкции множественных вставок параметризованы и имеют идентичный SQL, поэтому одну и ту же подготовленную инструкцию можно использовать повторно.
Тем не менее, если вы массово импортируете огромное количество записей, возможно, все же стоит использовать поддержку низкоуровневого КОПИРОВАНИЯ Npgsql. Я настоятельно рекомендую написать быстрый тест с помощью BenchmarkDotNet и сравнить различные решения с вашим собственным сценарием.
Комментарии:
1. Что ж, согласитесь с этим. Но обычно, когда у людей возникает вопрос «почему они не генерируют такой запрос», у них возникают проблемы с производительностью. Кроме того, в ядре EF невозможно запустить и забыть вставить, особенно если есть поля, созданные базой данных.
2. Несколько раундов против одного-это совсем другой вопрос, чем обновления «выстрели и забудь». В PostgreSQL поля, созданные базой данных (например, идентификаторы), извлекаются с помощью предложения RETURN, которое имеет очень мало накладных расходов, помимо фактической передачи значения (например, без дополнительных обходов), поэтому это вряд ли будет источником проблем с perf. В любом случае выше нет никаких указаний на проблему perf, просто вопрос о том, как выполняется вставка.
Ответ №2:
Именно так работает EF. Вы не можете ничего вставлять/обновлять/удалять без отслеживания изменений. И это неэффективно, если записей много. В PostgreSQL есть КОПИЯ для вставки большого количества записей, и если вы беспокоитесь о производительности, вы можете использовать такую возможность, предоставляемую Npgsql.
Хотя существует быстрый способ вставки записей, это механизм очень низкого уровня, который требует больших усилий и точного сопоставления, чтобы он работал.
Таким образом, существует множество расширений ядра EF, которые могут заставить его работать с минимальными усилиями. Одним из них является linq2db.EntityFrameworkCore, обратите внимание, что я один из создателей, и мое мнение может быть субъективным.
После установки библиотеки вы можете просто позвонить BulkCopy
, чтобы вставить пакет записей.
await context.BulkCopyAsync(items);
Существуют также параметры настройки, которые могут повысить производительность.