写点什么

挖掘 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:143070
用户头像

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

关注

评论

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

Mysql大法-Mysql索引失效VS Mysql存储引擎

知识浅谈

8月月更

DTSE 技术讲座 |云原生架构下的数字身份治理实践

华为云开发者联盟

云计算 云原生 后端 SaaS

记一次血淋淋的MySQL崩溃修复案例

华为云开发者联盟

数据库 后端

Solana流支付协议Zebec完成850万美元融资,CircleVentures等参投

小哈区块

JVM性能调优都做了什么?阿里内网JVM虚拟机性能调优指南给出了答案

退休的汤姆

程序员 JVM 面经 社招 秋招

前端工资涨不上去?可能是你没掌握构建工具:关于 Webpack、Babel、esbuild、Vite、Rollup、Parcel、SWC......的那些事

代码与野兽

前端 前端架构 前端工程化 webpack babel

采访236位第一批秋招上岸的同学后,我整理了这份Java面试手册

收到请回复

Java 架构 面试 语言 & 开发 秋招

RT-Thread记录(十八、I2C软件包 — 温湿度传感器 SHT21与EEPROM 24C02)

矜辰所致

软件包 RT-Thread 8月月更

购物体验值急转直下?消费体验的症结和解药在这里!

创意时空

[JS真好玩] InfoQ创作者必备: 监控每天是谁取关了你?

HullQin

CSS JavaScript html 前端 8月月更

面对数字化转型,金融ITer要补的第一堂课:运营

三少爷的见

数字化转型 运营 数据运营 金融业cio指南 证券行业

后端开发必备:mysql数据库建表的15个小技巧

Java永远的神

MySQL 数据库 程序员 面试 后端

Python图像处理丨图像的灰度线性变换

华为云开发者联盟

Python 人工智能

被裁后半月面试8家公司无果,凭借这份Java面试指南成功入职阿里

收到请回复

Java 架构 语言 & 开发

契约测试的三种模式

agnostic

契约测试

MySQL常见面试题

浅羽技术

MySQL 数据库 面试 后端 8月月更

英特尔推出数据中心GPU Flex系列,以开放式软件堆栈助力开发者

科技之家

并发量很大?阿里上传在GitHub的亿级流量百万并发手册爆火

退休的汤姆

Java 程序员 阿里 并发 秋招

认识微服务 SpringCloud (史上最全学习路线)

微服务 spring could 8月月更

【导航】RT-Thread 学习专栏目录 【快速跳转】

矜辰所致

目录 RT-Thread 8月月更

蚂蚁金服开源的这份SpringBoot笔记,曾在24小时内GitHub星标48k

收到请回复

Java 架构 面试 语言 & 开发 秋招

后端面试必备知识点

浅羽技术

Java 面试 后端 8月月更

云原生(二十七) | Kubernetes篇之自建高可用k8s集群前置概念与操作

Lansonli

云原生 k8s 8月月更

Solana流支付协议Zebec完成850万美元融资,CircleVentures等参投

西柚子

史上秋招最全500道Java面试题:JVM+分布式+算法+锁+MQ+微服务+数据库

退休的汤姆

Java 程序员 社招 Java工程师 秋招

“阿里爸爸”最新Java面试指南,基础+框架+数据库+系统设计+算法

收到请回复

Java 架构 计算机 语言 & 开发

1个理念4个步骤,快速上手客户体验管理

创意时空

拆解实体门店转型升级中的体验思维

创意时空

Solana流支付协议Zebec完成850万美元融资,CircleVentures等参投

股市老人

想要达到阿里P6?最少啃完这本500页Java并发多线程源码笔记

收到请回复

Java 程序员 架构 技术管理 语言 & 开发

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