ef core, почему он генерирует этот запрос вместо простой вставки? (сохранить граф объектов с байтом [] внутри) и связанные с этим проблемы производительности - PullRequest
0 голосов
/ 27 марта 2019

Я импортирую данные из устаревшей БД в новый проект, я немного озадачен некоторыми SQL-запросами, сгенерированными EF Core (я посмотрел на него в выходном представлении, поскольку он работал очень плохо по сравнению с тем, что я ожидается).

Я нацеливаюсь на SQL Server и создаю объекты, которые имеют свойства типа Image (poco). Вот пример того, как он используется для объекта с таким свойством:

MyObject.Thumbnail = new Image()
                {
                    Name = Thumbnail.GetValue("Name"),
                    OriginalData = ImageData,
                    Data = ImageData,
                    Width = bmp.Width,
                    Height = bmp.Height,
                    Format = ImageFormat.Jpg
                };

Меня смущает сгенерированный SQL (и, честно говоря, я его не понимаю, он объявляет временную таблицу, а затем объединяется? Почему?) И ее производительностью (для вставки 10 элементов требуется 17 секунд). с двумя свойствами изображений каждое, я запускаю SQL Server локально на той же машине, что и основной процесс .net, выполняющий запросы, поэтому нет никакой латентности сети и пропускной способности inifnite, а байтовых массивов и достаточно небольших для начала, в основном в Диапазон 300 КБ).

Ожидаемая производительность будет устранять один-два нуля.

Microsoft.EntityFrameworkCore.Database.Command:Information: Executed DbCommand (17,211ms) [Parameters=[@p0='?' (Size = -1) (DbType = Binary), @p1='?' (Size = 4000), @p2='?' (DbType = Int32), @p3='?' (DbType = Int32), @p4='?' (Size = 4000), @p5='?' (Size = -1) (DbType = Binary), @p6='?' (DbType = Int32), @p7='?' (Size = -1) (DbType = Binary), @p8='?' (Size = 4000), @p9='?' (DbType = Int32), @p10='?' (DbType = Int32), @p11='?' (Size = 4000), @p12='?' (Size = -1) (DbType = Binary), @p13='?' (DbType = Int32), @p14='?' (Size = -1) (DbType = Binary), @p15='?' (Size = 4000), @p16='?' (DbType = Int32), @p17='?' (DbType = Int32), @p18='?' (Size = 4000), @p19='?' (Size = -1) (DbType = Binary), @p20='?' (DbType = Int32), @p21='?' (Size = 8000) (DbType = Binary), @p22='?' (Size = 4000), @p23='?' (DbType = Int32), @p24='?' (DbType = Int32), @p25='?' (Size = 4000), @p26='?' (Size = 8000) (DbType = Binary), @p27='?' (DbType = Int32), @p28='?' (Size = -1) (DbType = Binary), @p29='?' (Size = 4000), @p30='?' (DbType = Int32), @p31='?' (DbType = Int32), @p32='?' (Size = 4000), @p33='?' (Size = -1) (DbType = Binary), @p34='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DECLARE @inserted0 TABLE ([Id] int, [_Position] [int]);
MERGE [Images] USING (
VALUES (@p0, @p1, @p2, @p3, @p4, @p5, @p6, 0),
(@p7, @p8, @p9, @p10, @p11, @p12, @p13, 1),
(@p14, @p15, @p16, @p17, @p18, @p19, @p20, 2),
(@p21, @p22, @p23, @p24, @p25, @p26, @p27, 3),
(@p28, @p29, @p30, @p31, @p32, @p33, @p34, 4)) AS i ([Data], [Description], [Format], [Height], [Name], [OriginalData], [Width], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Data], [Description], [Format], [Height], [Name], [OriginalData], [Width])
VALUES (i.[Data], i.[Description], i.[Format], i.[Height], i.[Name], i.[OriginalData], i.[Width])
OUTPUT INSERTED.[Id], i._Position
INTO @inserted0;

1 Ответ

3 голосов
/ 27 марта 2019

Для пакетов SQL Server SaveChanges по умолчанию. Для этого сценария (загрузка данных BLOB-объектов) пакетирование на самом деле плохо, так как вы не хотите, чтобы огромный набор параметров связывался с клиентом и сервером, а затем проходился для загрузки. Вам нужны пакеты с одной вставкой (или, если ваши большие двоичные объекты действительно большие, SqlClient Streaming , для которых вам нужно перейти в ADO.NET).

Вы конфигурируете это в той же строке, в которой вы указываете DbContext использовать SQL Server, например:

optionsBuilder.UseSqlServer(constr, b => b.MaxBatchSize(1).UseRelationalNulls(true) );

Чтобы отключить пакетную обработку и отказаться от создания запросов, эмулирующих семантику сравнения нулей в C #.

Если вам нужно условно отключить пакетирование, вы можете добавить параметр конструктора DbContext, который вы читаете в OnConfiguring. EG

public class Db : DbContext
{
    bool disableBatching = false;

    public Db() : base()
    {

    }
    public Db(bool disableBatching)
    {
        this.disableBatching = true;
    }

И если вам нужно убедить свой DI-контейнер иногда выдавать DbContexts с отключенной пакетной обработкой, вы можете создать для этого новый подтип, так как большинство DI-контейнеров работают без регистрации типов. EG:

public class NoBatchingDb : Db
{
    public NoBatchingDb() : base(disableBatching: true) { }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...