实体框架首先在DB中的AddRange上滥用sp_execsql

时间:2016-12-13 16:04:12

标签: c# sql-server entity-framework

我有一个使用EF 6.1的数据库第一个模型。

我需要大量导入数据。在Mysql中,将整个流拆分为500个元素和AddRange的较小集合,从而产生合理的插入性能(我还通过使代码并行并对线程数进行基准测试来调整代码)。

在SQL Server上运行时,相同的代码会产生可怕的性能。 SQL Server探查器显示EF尝试将每个实体作为单独的INSERT插入,但不使用普通的INSERT,而是依赖于sp_executesql

示例:

    public int Save(IList<BaseEntity> entities)
    {
        using (var dataContext = GetDataContext())
        {
                using (var tx = dataContext.Database.BeginTransaction())
                {
            dataContext.Configuration.AutoDetectChangesEnabled = false;
            dataContext.Configuration.ValidateOnSaveEnabled = false;
            dataContext.Configuration.LazyLoadingEnabled = false;

            var sa = entities.OfType<A>();
            var sd = entities.OfType<D>();
            var se = entities.OfType<E>();
            var sf = entities.OfType<F>();
            var sg = entities.OfType<G>();
            var sh = entities.OfType<H>();

            dataContext.sezione_a.AddRange(sa);
            dataContext.sezione_d.AddRange(sd);
            dataContext.sezione_e.AddRange(se);
            dataContext.sezione_f.AddRange(sf);
            dataContext.sezione_g.AddRange(sg);
            dataContext.sezione_h.AddRange(sh);

            int ret = dataContext.SaveChanges();

                 tx.Commit();
            return ret
            }
        }
    }

这是因为我的列表包含多个实体的混合,但整个列表最多可以计数500个。更多线程同时调用此方法。

当我运行探查器时,我可以看到

exec sp_executesql N'INSERT [dbo].[sezione_a]([A01], [A01a], [A01b], [A02], [A03], [A11], [A12], [A12a], [A12b], [A12c], [A21], [A22], [A23], [A24], [A25], [A31], [A31a], [A31b], [A32], [A33], [A33a], [A33b], [A33c], [A34], [A41], [A42], [A43], [A51], [A52], [A53], [A54], [A54a], [A54b], [A54c], [B11], [B12], [B13], [B14], [B15], [Z0], [progA], [utente])
VALUES (@0, @1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16, @17, @18, @19, @20, @21, @22, @23, @24, @25, @26, @27, @28, @29, @30, @31, @32, @33, @34, @35, @36, @37, @38, @39, @40, @41)
',N'@0 varchar(13),@1 varchar(2),@2 varchar(11),@3 varchar(1),@4 varchar(20),@5 varchar(6),@6 varchar(38),@7 varchar(6),@8 varchar(30),@9 varchar(2),@10 varchar(8),@11 varchar(1),@12 varchar(1),@13 varchar(4),@14 varchar(2),@15 varchar(13),@16 varchar(2),@17 varchar(11),@18 varchar(3),@19 varchar(38),@20 varchar(6),@21 varchar(30),@22 varchar(2),@23 varchar(50),@24 varchar(25),@25 varchar(1),@26 varchar(1),@27 varchar(8),@28 varchar(2),@29 varchar(12),@30 varchar(29),@31 varchar(1),@32 varchar(8),@33 varchar(20),@34 varchar(1),@35 varchar(3),@36 varchar(1),@37 decimal(18,2),@38 decimal(18,2),@39 varchar(69),@40 bigint,@41 int',@0='0907084500011',@1='09',@2='07084500011',@3='1',@4='20110209100276666600',[...]

每个记录都会重复此操作。

我已经检查了其他批量插入策略,但由于我的应用程序需要可以在MS SQL和Mysql中移植,所以我不能依赖依赖于SqlBulkCopy的其他库。我的意思是我想使用相同的代码。

Mysql看起来像是为6个表中的每个表压缩插入到单个INSERT中。 SQL Server看起来没有。

我还检查了我的edmx模型,在阅读了varcharnvarchar问题之后,我将所有列标准化为varcharUnicode="false"直接进入xml。 / p>

但那没用。

我可以做什么让EF将INSERT纳入单一陈述并获得不错的表现? 500行的200秒是不可接受的。

1 个答案:

答案 0 :(得分:1)

Entity Framework使用ADO.NET,当使用paramterized SQL时,总是使用sp_executesql - 为什么这会让你担心? EF 6不支持批处理INSERT,它在EF Core中可用。为了快速,批量更新使用带有表值参数的ADO.NET和SqlClient SqlBulkCopy API