c# - 是什么导致 EF 插入比普通 ADO.NET 慢得多?

标签 c# asp.net .net entity-framework

我必须在数据库中记录 Web 服务调用。一开始,我使用code first EF来定义Entity类和生成数据库脚本。数据库部分很简单,就一张表。有一个主键:Id,其他列是string、datetime和float。共16列。

然后我跑了VS2012的性能分析。报告显示 RecordUsageEF 消耗了整个调用的一半时间,这很荒谬。我尝试了 MergeOption.NoTracking 选项和预生成 View (How to: Pre-Generate Views to Improve Query Performance)。但他们并没有太大帮助。

然后我尝试了 Ado.net。我将sql脚本放在源代码中只是为了测试。一起调用 2 个方法来比较性能。

    public static void RecordUsage(HttpContext httpContext, XmlWDCRecipe processedRecipe, string orgRecipe, string userName, ActionEnum action, bool trueview, string pageId)
    {                                                                                               
        RecordUsageEF(httpContext, processedRecipe, orgRecipe, userName, action, trueview, pageId);
        RecordUsageADO(httpContext, processedRecipe, orgRecipe, userName, action, trueview, pageId);
    }

结果让我大吃一惊:
enter image description here

更新使用静态 EF 上下文改进了一些:
enter image description here

内部记录使用EF:
enter image description here

已更新 RecordUsageEF 内部 -- 静态上下文
enter image description here

更新刚刚发现默认的Performance是CPU采样,这里是选择Instrumentation时的结果
enter image description here

还不错,但如果 CPU 是网站/网络服务的瓶颈。 EF 看起来不是很好的选择。

我在 sql profiler 中检查了 EF 生成的脚本。这是一个非常简单的插入 sql 语句,它比 Ado.net 运行得更快。

EF 是否遗漏了什么?如果达到这种性能水平,我将无法使用 EF。

这里是源代码。
EF 版本:

public static readonly LogContainer container = new LogContainer();

private static void RecordUsageEF(HttpContext httpContext, XmlWDCRecipe processedRecipe, string orgRecipe, string userName, ActionEnum action, bool trueview, string pageId)
    {
        {
            container.Usages.MergeOption = System.Data.Objects.MergeOption.NoTracking;
            using (LookupService ls = new LookupService(httpContext.Server.MapPath(geoDBLocation), LookupService.GEOIP_MEMORY_CACHE))
            {
                //get country of the ip address
                Location location = s.getLocation(httpContext.Request.UserHostAddress);


                Usage usage = new Usage()
                {
                    Brand = brand,
                    Action = action.ToString(),
                    ExecuteDate = DateTime.Now,
                    OutputFormat = trueview ? Path.GetExtension(processedRecipe.Output.trueview_file) : Path.GetExtension(processedRecipe.Output.design_file),
                    Recipe = orgRecipe,
                    SessionId = pageId,
                    Username = userName,
                    ClientIP = httpContext.Request.UserHostAddress,
                    ClientCountry = location == null ? null : location.countryName,
                    ClientState = location == null ? null : location.regionName,
                    ClientCity = location == null ? null : location.city,
                    ClientPostcode = location == null ? null : location.postalCode,
                    ClientLatitude = location == null ? null : (double?)location.latitude,
                    ClientLongitude = location == null ? null : (double?)location.longitude,
                    UserAgent = httpContext.Request.UserAgent
                };

                //container.AddToUsages(usage);
                container.Usages.AddObject(usage);                   
                container.SaveChanges(System.Data.Objects.SaveOptions.None);
            }
        }     
    }

EF 设置为默认值:
enter image description here

Ado.net 版本:

    private static void RecordUsageADO(HttpContext httpContext, XmlWDCRecipe processedRecipe, string orgRecipe, string userName, ActionEnum action, bool trueview, string pageId)
    {
        using (SqlConnection conn = new SqlConnection("data source=pgo_swsvr;initial catalog=OESDWebSizer;user id=sa;password=sa;MultipleActiveResultSets=True;"))
        {

            using (LookupService ls = new LookupService(httpContext.Server.MapPath(geoDBLocation), LookupService.GEOIP_MEMORY_CACHE))
            {
                //get country of the ip address
                //test using "203.110.131.5"  "58.63.236.236"
                //httpContext.Request.UserHostAddress
                Location location = ls.getLocation(httpContext.Request.UserHostAddress);


                SqlCommand command = new SqlCommand();
                conn.Open();
                command.Connection = conn;
                command.CommandType = System.Data.CommandType.Text;
                command.CommandText = @"insert into Usages ([Brand],[Username],[SessionId],[Action],[Recipe],[ExecuteDate]
                                       ,[OutputFormat],[ClientIP],[ClientCountry],[ClientState],[ClientCity],[ClientPostcode]
                                       ,[ClientLatitude],[ClientLongitude],[UserAgent])
                                        Values ('" + brand + "'," 
                                        + (string.IsNullOrEmpty(userName) ? "NULL" : "'" + userName + "'") + ", '" + pageId + "', '" + action.ToString() + "', '" + orgRecipe + "', '" + DateTime.Now.ToString("yyyyMMdd") + "', '"
                                        + (trueview ? Path.GetExtension(processedRecipe.Output.trueview_file) : Path.GetExtension(processedRecipe.Output.design_file)) + "', '"
                                        + httpContext.Request.UserHostAddress + "', '"
                                        + (location == null ? string.Empty : location.countryName) + "', '"
                                        + (location == null ? string.Empty : location.regionName) + "', '"
                                        + (location == null ? string.Empty : location.city) + "', '"
                                        + (location == null ? string.Empty : location.postalCode) + "', "
                                        + (location == null ? 0 : (double?)location.latitude) + ", "
                                        + (location == null ? 0 : (double?)location.longitude) + ", '"
                                        + httpContext.Request.UserAgent + "')";

                command.ExecuteNonQuery();

            }
        }
    }

最佳答案

Entity Framework 将许多细节抽象为(某些)CPU 性能的成本。 Microsoft 有一篇文章详细介绍了性能注意事项: Performance Considerations (Entity Framework)

关于c# - 是什么导致 EF 插入比普通 ADO.NET 慢得多?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11751006/

相关文章:

.net - ActiveX,安装不工作

c# - 如何在 ASP.NET Web API 中使用缓存?

javascript - 从 UpdatePanel 异步回发后,嵌入式 javascript 不起作用

asp.net - 从 VB.NET 类中检查 IsPostBack 或 IsCallBack 的方法

asp.net - Twitter Bootstrap - 模态格式的表单 - ASP.NET

.net - .NET 上服务层的扩展策略

c# - Directory.GetFiles() 抛出异常 - 文件夹名称末尾有空格无法识别

c# - 如何清除 C# 中的事件订阅?

c# - 如何在 C# 中创建原始数据类型?

.net - Authbot 登录服务返回链接,显示 "ClientID not supported for this API"