写点什么

挖掘 ADO.NET Entity 框架的性能

  • 2008-02-23
  • 本文字数:2358 字

    阅读完需:约 8 分钟

ADO.NET 团队最近讨论了 ADO.NET Entity 框架的各种性能特征。ADO.NET Entity 框架在 12 月已经进入它的第三个 beta 版本,自那时起开发团队就开始为开发人员提供了使用该框架的相关信息。而现在,则为开发人员提供了框架性能方面的信息。

本文鞭辟入里地介绍了 ADO.NET Entity 框架的性能,演示了如何提高简单查询速度的方法,并阐释了框架的性能特征。

需要重点指出的是,当一个抽象层或者类似 EDM(译注:指 Entity Data Model)的模块被用来转换数据库的关系样式时,会带来一定的性能损失。

查询与结果

本文使用了 NorthWind 数据库作为模型,并创建了一个简单查询:

(NorthwindEntities ne =  NorthwindEntities()) <br></br>{ <br></br> (Order o  ne.Orders) <br></br>    { <br></br> i = o.OrderID; <br></br>    } <br></br>}

测试时,我们的每个查询对整个 848 行数据进行了 10 次遍历。结果很有意思,第 1 次运行时耗费了 4241 毫秒,而接下来的每次运行则平均耗费 13 毫秒左右的时间。最耗时的一部分内容是 ObjectContext 的创建,而在执行任意一个访问数据库的操作时,都会有一些耗时的操作发生。

每次操作的百分比值可以给我们一些启示:

  • 装载元数据(11%)
  • 初始化元数据(14%)
  • 打开连接(8%)
  • 生成视图(56%)
  • 装载程序集(2%)
  • 跟踪(1%)
  • 实例化(7%)
  • 其它(1%)

耗时百分比值最大的是视图生成,它达到了惊人的 56%。既然视图生成是造成性能损耗的罪魁祸首,那么开发人员最好是使用命令行工具 EDM 生成器(EdmGen.exe),运行时需要加上视图生成命令参数(/mode:ViewGeneration),它的输出内容为一个代码文件(C#或者 VB.NET),可以包含在项目中。视图的预生成可以将启动时间降低到 2933 毫秒,而对于循环遍历操作,整个时间可以降低 28%。生成视图并随着应用程序一起发布是提高性能的妙方,但其缺点则在于视图不再是动态的,一旦模型发生改变,就需要重新生成以保持同步。

查询性能

需要指出的是关于性能的主要设计要素是查询缓存。一旦执行了查询,它的一部分内容就被维持在全局缓存中。由于查询与元数据缓存的存在,使得第二次运行的执行速度总是比第一次运行快。例如,如下的 Entity SQL 查询:

(PerformanceArticleContext ne = PerformanceArticleContext()) <br></br>{ <br></br> ObjectQuery<Orders> orders = ne.CreateQuery<Orders>(); <br></br> (Orders o orders) <br></br> { <br></br> i = o.OrderID; <br></br> } <br></br>}

第一次运行该查询耗时 179 毫秒,但下一次运行则只耗费了 15 毫秒的时间。首次运行与后续运行在执行方面的区别在于它构建了能够为执行传递 provider 的命令树(command tree)。

LINQ 查询在执行方式上与 Entity SQL 查询相似。例如,下面的查询:

(PerformanceArticleContext ne = PerformanceArticleContext()) <br></br>{ <br></br> var orders = from order ne.Orders <br></br> select order; <br></br> (Orders o orders) <br></br> { <br></br> i = o.OrderID; <br></br> } <br></br>}

首次执行 LINQ 查询耗时 202 毫秒,而随后的执行耗时 18 毫秒,两者的差距还要低于 Entity SQL。可以看到,使用编译了的 LINQ 查询对于性能的提高更为明显。编译 LINQ 查询的好处在于它构建了表达树(expression tree),当查询被编译时,后续的执行就不需要重建表达树了。编译的 LINQ 查询代码看起来像这样:

Func<PerformanceArticleContext, IQueryable<Orders>> compiledQuery = CompiledQuery.Compile((PerformanceArticleContext ne) => (from o ne.Orders select o)); <br></br>(PerformanceArticleContext ne = PerformanceArticleContext()) <br></br>{ <br></br> (Orders o compiledQuery(ne)) <br></br> { <br></br> i = o.OrderID; <br></br> } <br></br>}

注意,PerformanceArticleContext 是一个委托。对于编译了的 LINQ 查询而言,第一次执行耗时 305 毫秒,而随后的执行时间则为 15 毫秒。结果并不惊人,值得关注的是编译的 LINQ 查询比之常规方式的 LINQ 查询,执行时间少了 3 毫秒。或许对于几个查询而言,这算不上什么,但如果有数以千计的查询,这样的性能提升就倍显价值所在了。

ADO.NET 团队建议开发人员在查询中应谨慎使用 Track/NoTrack 选项:

在之前的例子中,所有放在对象创建中的查询结果都被添加到 ObjectStateManager 中,因此我们能够跟踪它们的更新。如果没有必要跟踪对象的更新和删除,那么最好是使用 NoTracking 合并项。例如,在一个 ASP.NET Web 应用程序中,如果它要查询一个指定的分类名称,但却不需要对返回的数据进行更新,那么 NoTracking 就会是一个不错的选择。在这种情形下,使用 NoTracking 的查询会在性能方面得到改善。

基于前面的一组数字,NoTracking 选项能够大幅度地降低执行的时间,而其中性能的提升主要源自于我们停止了对变更的跟踪以及对关系的管理。如果使用 NoTracking 查询,无论是第一次执行还是随后的执行,编译的 LINQ 查询都要优于标准的 LINQ 查询。注意,编译的 LINQ 查询的第二次执行与 Entity SQL 查询的第二次执行相等。

ADO.NET 团队同时还提醒开发者在创建查询时,有一些内容必须铭记于心:

在 Entity 框架中优化查询性能时,应该针对特定的编程场景做出最佳选择。这里列举了几个关键项:

  • ObjectContext 的首次创建包含了装载和验证元数据的性能损耗。
  • 任何一个查询的首次执行都包含了构建一个查询缓存的性能损耗,以利于提高后续查询的执行速度。
  • 编译的 LINQ 查询比未编译的 LINQ 查询要快。
  • 如果不需要跟踪数据的变更与数据的关系,或者对大数据对象进行流操作,那么通过 NoTracking 合并项执行查询,效果会更佳。

若要了解更多关于 ADO.NET 和 Entity 框架的信息,敬请访问 ADO.NET 的团队博客

查看英文原文: Digging into the Performance of the ADO.NET Entity Framework

2008-02-23 08:143017
用户头像

发布了 79 篇内容, 共 17.7 次阅读, 收获喜欢 1 次。

关注

评论

发布
暂无评论
发现更多内容

当我们谈前端性能的时候,我们谈的是什么

vivo互联网技术

性能优化 大前端 页面

为什么建议使用你 LocalDateTime ,而不是 Date?

Bruce Duan

LocalDateTime Date

AR智能眼镜会成未来趋势

anyRTC开发者

人工智能 音视频 WebRTC RTC

《迅雷链精品课》第十一课:区块链常用共识算法介绍

迅雷链

区块链

警察营救安徽望江县17岁女生跳河自尽过程中,现场看热闹的旁观者们在做什么?

wbliu85

「生产事故」MongoDB复合索引引发的灾难

Kerwin

数据库 mongodb

5种分布式事务方案与阿里的 Seata 中间件

Bruce Duan

分布式事务 seata

数据结构与算法系列之散列表(一)(GO)

书旅

数据结构 算法 Go 语言

G20200388020528第二周作业

走走,停停……

话题讨论 | 图解一致性哈希算法全小区局域网最通俗易懂

程序员柠檬

Kubernetes 1.20发布,Release Logo变成一只猫

晓川

《前端算法系列》数组去重

徐小夕

Java 面试 算法 大前端

悟空活动中台-打造 Nodejs 版本的MyBatis

vivo互联网技术

Java 大前端 mybatis nodejs

2020 阿里云原生实战峰会即将开幕 云原生落地的正确姿势

阿里巴巴云原生

阿里巴巴 阿里云 开发者 云原生 实战

(G20200388020528)第一周练习

走走,停停……

通过docker获取系统运行情况的实用命令

晓川

一个依赖搞定 Spring Boot 反爬虫,防止接口盗刷!

Bruce Duan

反爬虫组件 kk-anti-reptile

即构科技肖传发:即刻构建在线教育的音视频互动场景

ZEGO即构

大厂也在用的 6种 数据脱敏方案,严防泄露数据的 “内鬼”

程序员小富

Java 数据脱敏;

话题讨论 | 作为地地道道的程序员半年内都没摸过代码是什么样的体验?

xcbeyond

话题讨论

架构师训练营第一期 - 第十一周课后作业

卖猪肉的大叔

极客大学架构师训练营

公安舆情分析重点人员管控系统搭建解决方案

t13823115967

智慧公安 舆情分析

药品安全追溯系统开发区块链技术

13828808769

安全 区块链+

区块链应用落地,区块链电子票据应用平台搭建

t13823115967

区块链+ 区块链应用 区块链落地开发

DB-Engines 12月数据库排名: PostgreSQL拿下同期涨幅榜冠军,有望获得「2020年度数据库」荣誉?

华章IT

数据库 postgresql

Redis 如何实现点赞、取消点赞

Bruce Duan

Redis实现点赞

ZEGO即构科技荣获36氪【WISE2020中国新经济之王最具影响力企业】

ZEGO即构

读写分离这个坑,你应该踩过吧?

楼下小黑哥

MySQL 主从同步 读写分离

排查指南 | 当 mPaaS 小程序提示“应用更新错误(1001)”时

蚂蚁集团移动开发平台 mPaaS

小程序 问题排查 mPaaS

TronChain波场链系统软件开发|TronChain波场链APP开发

系统开发

从容应对11.11大促 京东智联云云硬盘做对了哪些事?

京东科技开发者

云计算 高可用 云硬盘

挖掘ADO.NET Entity框架的性能_.NET_Robert Bazinet_InfoQ精选文章