ToListAsync в Entity Framework Снова Быстрый
Если вы извлекаете очень большую строку NVARCHAR(MAX) через await ToListAsync(), Entity Framework будет делать что-то непонятное, что приводит к медленному запросу и большому объёму выделения памяти. На самом деле, виновник не совсем Entity Framework. Основную работу выполняет базовый Microsoft.Data.SqlClient. Проблема в том, что он неправильно использует SqlDataReader.
Замечание: это касается в основном пакета/реализации для SqlServer, поскольку он использует пакет Microsoft.Data.SqlClient.
Вот вырезка из бенчмарка от @Wraith2:
| Method | Mean | Allocated |
|------- |----------:|----------:|
| Async | 757.51 ms | 101.49 MB |
| Sync | 39.40 ms | 80.14 MB |
Microsoft.Data.SqlClient 6.1.0
@Wraith2 исправил проблему серией пул-реквестов, на протяжении более 5 лет! Это невероятно. Конечно, он не работал над исправлениями непрерывно 5 лет, но всё равно это очень впечатляет. Последние заметки о выпуске можно прочитать здесь. Обратите внимание на материалы "Added packet multiplexing support to improve large data read performance" (Добавлена поддержка мультиплексирования пакетов для повышения производительности чтения больших объёмов данных).
А пул-реквест, исправляющий проблему, находится здесь.
Результаты такие:
| Async | 49.45 ms | 101.51 MB |
| Sync | 40.09 ms | 80.14 MB |
Разрыв в выделении памяти в 20% всё ещё сохраняется, но время уже сопоставимо. Wraith2 и команда проделали потрясающую работу. Вы можете протестировать превью версию пакета, даже используя EF, поскольку прямые зависимости переопределяют транзитивные. Либо подождите следующего релиза EF, включающего новую версию Microsoft.Data.SqlClient 6.1.0, который должен уже скоро выйти.
Источник: https://steven-giesel.com/blogPost/dd7ab934-c311-45e0-9a04-9a28c624b957/tolistasync-is-fast-again-in-entity-framework-kind-of