EF 6.0 SaveAll()非常慢

时间:2016-02-29 14:29:00

标签: c# sql performance entity-framework

我正在使用EF并使用此功能保存我的POCO对象:

public void SaveAll(IList<CoreEntity> entitaCoreList)
{
    bool result = false;

    using (var context = new NSTEntities())
    {
        //context.Configuration.AutoDetectChangesEnabled = false;
        foreach (var entitaCore in entitaCoreList)
        {
            TRACCIAVEICOLO_T500 tracciamentoVeicoliEF = new TRACCIAVEICOLO_T500();
                           tracciamentoVeicoliEF.C_IDTRACCIAMENTOVEICOLO = tracciaVeicolo.Id;
        CultureInfo ci = CultureInfo.CreateSpecificCulture("en-EN");
        tracciamentoVeicoliEF.Z_COORD = System.Data.Spatial.DbGeography.PointFromText(
            "POINT (" + tracciaVeicolo.Longitudine.ToString(ci) + " " + tracciaVeicolo.Latitudine.ToString(ci) + ")", 4326);
        tracciamentoVeicoliEF.D_DATARILEVAZIONE = tracciaVeicolo.DataRilevazione;
        tracciamentoVeicoliEF.C_CODICEWEBFLEET = tracciaVeicolo.CodiceVeicoloWebfleet;
        tracciamentoVeicoliEF.S_POSITIONSTRING = tracciaVeicolo.posString;
        tracciamentoVeicoliEF.P_TIPOMESSAGGIO = (int) tracciaVeicolo.TipoMessaggio;
        tracciamentoVeicoliEF.V_VELOCITA = tracciaVeicolo.Velocita;
        tracciamentoVeicoliEF.V_DIREZIONE = tracciaVeicolo.Direzione;
        tracciamentoVeicoliEF.S_GPSSTATUS = tracciaVeicolo.GpsStatus;
        tableSet.Add(tracciamentoVeicoliEF);
        }

        context.SaveChanges();
        }
    }
}

但它非常慢,1000条记录需要近25秒。 我尝试使用这样的原始查询:

        public void SaveRaw(List<TracciaVeicolo> v)
        {
            StringBuilder query = new StringBuilder();
query.Append(@"INSERT INTO [dbo].[TRACCIAMENTOVEICOLI_T500]([Z_COORD],[C_CODICEWEBFLEET],[D_DATARILEVAZIONE],[S_POSITIONSTRING],[P_TIPOMESSAGGIO],[V_VELOCITA],[V_DIREZIONE],[S_GPSSTATUS])VALUES ");
            bool first = true;
            foreach(var o in v)
            {
                if (!first)
                {
                    query.Append(",");
                }
                query.AppendFormat("(geography::Point(47.65100, -122.34900, 4326),'{0}','{1}','{2}',{3},{4},{5},'{6}')"
                    , o.CodiceVeicoloWebfleet
                    ,o.DataRilevazione.ToString("yyyy-dd-MM HH:mm:ss")
                ,o.posString
                , (int)o.TipoMessaggio
                , o.Velocita
                , o.Direzione
                , o.GpsStatus);
                first = false;
            }

            using (var context = new NSTEntities())
            {
                context.Database.ExecuteSqlCommand(query.ToString());
            }
        }

需要5秒钟。我使用EF错了吗?我也尝试使用context.Configuration.AutoDetectChangesEnabled = false;(正如您在第一个代码段中看到的那样),但它不会改变任何内容

EF运行的查询是这样的:

declare @p3 sys.geography
set @p3=convert(sys.geography,0xE6100000010CE9297288B82F44404DF4F92823263240)
exec sp_executesql N'insert [dbo].[TRACCIAMENTOVEICOLI_T500]([Z_COORD], [C_CODICEWEBFLEET], [D_DATARILEVAZIONE], [S_POSITIONSTRING], [P_TIPOMESSAGGIO], [V_VELOCITA], [V_DIREZIONE], [S_GPSSTATUS])
values (@0, @1, @2, @3, @4, @5, @6, @7)
select [C_IDTRACCIAMENTOVEICOLO]
from [dbo].[TRACCIAMENTOVEICOLI_T500]
where @@ROWCOUNT > 0 and [C_IDTRACCIAMENTOVEICOLO] = scope_identity()',N'@0 [geography],@1 nvarchar(20),@2 datetime2(7),@3 nvarchar(256),@4 int,@5 float,@6 int,@7 char(1)',@0=@p3,@1=N'1-83645-666EE1173',@2='2016-02-29 15:34:57',@3=N'Vicino a Lecce, 1a Lecce Centro-1B ',@4=0,@5=8,3333333333333339,@6=50,@7='A'

2 个答案:

答案 0 :(得分:0)

您可以尝试combining several operations into one transaction执行它。这将为您节省大量时间,当您执行单个操作时,这会占用网络延迟。

using (var context = new NSTEntities())
{
    using (var dbContextTransaction = context.Database.BeginTransaction()) 
    {
        try 
        { 
            [... foreach ... tableSet.Add(...) ...]

            context.SaveChanges(); 

            dbContextTransaction.Commit(); 
        } 
        catch (Exception exception) 
        { 
            dbContextTransaction.Rollback();
            // Log exception (never ignore)
        } 
    }
}

您还可以log the SQL-operations确定发生了什么。 例如,使用以下内容:context.Database.Log = s => Debug.WriteLine(s);

答案 1 :(得分:0)

正如您所注意到的,实体框架SaveChanges非常慢,因为每次更改都会进行数据库往返。

他们有一些您可以使用的最佳做法,例如使用 AddRange 而不是“添加”,但最后,您仍会遇到一些性能问题,因为将执行1000次数据库往返。

免责声明:我是该项目的所有者Entity Framework Extensions

显着提高性能的一种方法是使用允许使用批量操作的第三方库。

public void SaveAll(IList<CoreEntity> entitaCoreList)
{
    bool result = false;

    using (var context = new NSTEntities())
    {
        // ... code ...

        context.BulkSaveChanges();
    }
}