问题

你想为多次用到的查询提高性能,而且你不想添加额外的编码或配置.

解决方案

假设你有如Figure 13-8 所示的模型

Figure 13-8. A model with an Associate and its related Paycheck

在这个模型里,每个Associate(同事)有0到多个Paychecks(薪水),你有一个LINQ查询,它在你的整个应用程序中重复使用,你想仅编译一次,然后复用这个已编译的版本,通过这种方式来提高这个查询性能。

当针对数据库执行时,EF必须把你的强类型的LINQ查询转换成对应的SQL查询(基于你的数据库引擎,SqlServer,Oracle等等),在EF5时,每个查询转换在默认情况下会被缓存,这个过程与“自动缓存”相关,后面的每次LINQ查询,都直接从“查询计划缓存”里重新取回,这样就绕过了转换的步骤.对于包含参数的查询,改变参数值,仍然会重新获取相同的查询.有趣地是,这个”查询计划缓存”在同一个应用程序域里的上下文对象里共享,也就是说,一旦缓存了,在同一个应用程序域里的任何一个上下文对象都访问它.

在Listing 13-10,我们比较了启用和禁用缓存的性能.为说明带来的性能,我们把LinQ查询的编译版本和非编译版本迭代10次的时间打印出来.在这个查询里,我们可以看到大致有2倍的性能提升.多数情况下是由于编译需要相对高的成本,而执行查询却只需要低的成本.

Listing 13-20. Comparing the Performance of a Simple Compiled LINQ Query

private static void RunUncompiledQuery()

{

using (var context = new EFRecipesEntities())

{

// Explicitly disable query plan caching

var objectContext = ((IObjectContextAdapter)context).ObjectContext;

var associateNoCache = objectContext.CreateObjectSet<Associate>();

associateNoCache.EnablePlanCaching = false;

var watch = new Stopwatch();

long totalTicks = 0;

// warm things up

associateNoCache.Include(x => x.Paychecks).Where(a => a.Name.StartsWith("Karen")).ToList();

// query gets compiled each time

for (var i = 0; i < 10; i++)

{

watch.Restart();

associateNoCache.Include(x => x.Paychecks).Where(a => a.Name.StartsWith("Karen")).ToList();

watch.Stop();

totalTicks += watch.ElapsedTicks;

Console.WriteLine("Not Compiled #{0}: {1}", i, watch.ElapsedTicks);

}

Console.WriteLine("Average ticks without compiling: {0}", (totalTicks / 10));

Console.WriteLine("");

}

}

private static void RunCompiledQuery()

{

using (var context = new EFRecipesEntities())

{

var watch = new Stopwatch();

long totalTicks = 0;

// warm things up

context.Associates.Include(x => x.Paychecks).Where(a => a.Name.StartsWith("Karen")).ToList();

totalTicks = 0;

for (var i = 0; i < 10; i++)

{

watch.Restart();

context.Associates.Include(x => x.Paychecks).Where(a => a.Name.StartsWith("Karen")).ToList();

watch.Stop();

totalTicks += watch.ElapsedTicks;

Console.WriteLine("Compiled #{0}: {1}", i, watch.ElapsedTicks);

}

Console.WriteLine("Average ticks with compiling: {0}", (totalTicks / 10));

}

}

输出结果如下:

Not Compiled #0: 10014

Not Compiled #1: 5004

Not Compiled #2: 5178

Not Compiled #3: 7624

Not Compiled #4: 4839

Not Compiled #5: 5017

Not Compiled #6: 4864

Not Compiled #7: 5090

Not Compiled #8: 4499

Not Compiled #9: 6942

Average ticks without compiling: 5907

Compiled #0: 3458

Compiled #1: 1524

Compiled #2: 1320

Compiled #3: 1283

Compiled #4: 1202

Compiled #5: 1145

Compiled #6: 1075

Compiled #7: 1104

Compiled #8: 1081

Compiled #9: 1084

Average ticks with compiling: 1427

它是如何工作的

当你运行一个LINQ查询时,EF为该查询创建一个表达式树对象,然后该对象转换或编译入一个内部命令树.该内部命令树会被传递给数据库提供者并被转换为相应的数据库命令(通常是SQL).转换一个表达式树的代价可能相当高,主要取决于查询复杂度和底层的模型.模型如果有很深层的继承或是很多的水平方向上的引入,会使得转换处理过程相当复杂,这样编译的所花的时间要比执行查询所花的时间多得多.然后在EF5为LINQ查询引入了查询自动缓存技术.你可以通过查看Listing 13-20 的执行结果里看出它所提高的性能.

另外,如Listing 13-20 所示,你也能禁用”自动编译”特性,通过DbContext对象的底层对象ObjectContext,得到一个实体对象的引用,并设置它的EnablePlanCaching属性为false.

为了跟踪每个已编译的查询,EF遍历查询表达式树节点,并创建一个哈希表,用它作为已编译查询的索引,为后面的每个调用,EF会先尝试从缓存查找哈希表的主键,以节省查询转换处理带来的成本.需要注意的是,”查询缓存计划”不依赖上下文对象,它是被绑定到应用程序的应用程序域,也就意味着,缓存的查询对于所有的上下文实例都是可用的.

当底层的查询缓存包含800或更多缓存计划时,每一分钟,一个清除处理会根据LFRU(least frequently/recently used使用次数最少,最近不用)算法(根据查询被命中的次数和它的时限)来移除一个缓存.

已编译的查询对Asp.net的分页查询尤其有用,分页查询的参数可能会改变,但是查询是一致的,也是能复用到每一页的展示上,这是因为一个已编译的查询是”被参数化的”,也就是说能接受不同的参数值.

Entity Framework 6 Recipes 2nd Edition(13-6)译 - 自动编译的LINQ查询相关推荐

  1. Entity Framework 6 Recipes 2nd Edition(9-1)译-用Web Api更新单独分离的实体

    第九章 在N层结构的应用程序中使用EF 不是所有的应用都能完全地写入到一个单个的过程中(就是驻留在一个单一的物理层中),实际上,在当今不断发展的网络世界,大量的应用程序的结构包含经典的表现层,应用程, ...

  2. Entity Framework 6 Recipes 2nd Edition(13-2)译 - 用实体键获取一个单独的实体

    问题 不管你用DBFirst,ModelFirst或是CodeFirst的方式,你想用实体键获取一个单独的实体.在本例中,我们用CodeFirst的方式. 解决方案 假设你有一个模型表示一个Paint ...

  3. Entity Framework 6 Recipes 2nd Edition(13-4)译 - 有效地创建一个搜索查询

    问题 你想用LINQ写一个搜索查询,能被转换成更有效率的SQL.另外,你想用EF的CodeFirst方式实现. 解决方案 假设你有如下Figure 13-6所示的模型 Figure 13-6. A s ...

  4. Entity Framework 6 Recipes 2nd Edition(10-6)译 - TPT继承模型中使用存储过程

    10-6. TPT继承模型中使用存储过程 问题 想在一个TPT继承模型中使用存储过程 解决方案 假设已有如Figure 10-6所示模型. 在模型里, Magazine(杂志) and DVD继承于基 ...

  5. Entity Framework 6 Recipes 2nd Edition(9-2)译-用WCF更新单独分离的实体

    9-2. 用WCF更新单独分离的实体 问题 你想通过WCF为一个数据存储发布查询,插入,删除和修改,并且使这些操作尽可能地简单 此外,你想通过Code First方式实现EF6的数据访问管理 解决方案 ...

  6. Entity Framework 6 Recipes 2nd Edition(12-1)译 - 当SaveChanges( ) 被调用时执行你的代码...

    第12章定制EF 在本章的小节里,定制实体对象和EF处理的一些功能.这些小节将涵盖很多"幕后"的事情,能让你的代码更加统一解决一些事情,比如用一个业务规则中心统一地为实体执行验证. ...

  7. Entity Framework 6 Recipes 2nd Edition(9-7)译-在WCF服务中序列化代理

    9-7. 在WCF服务中序列化代理 问题 从一个查询里返回一个动态代理对象,想要把它序列为一个POCO(Plain-Old CLR Objects)对象. 实现基于POCO实体对象, 在运行时,EF会 ...

  8. Entity Framework 6 Recipes 2nd Edition(10-5)译 - 在存储模型中使用自定义函数

    10-5. 在存储模型中使用自定义函数 问题 想在模型中使用自定义函数,而不是存储过程. 解决方案 假设我们数据库里有成员(members)和他们已经发送的信息(messages) 关系数据表,如Fi ...

  9. Entity Framework 6 Recipes 2nd Edition(10-3)译 - 返回结果是一个标量值

    10-3. 返回结果是一个标量值 问题 想取得存储过程返回的一个标量值. 解决方案 假设我们有如Figure 10-2所示的ATM机和ATM机取款记录的模型 Figure 10-2. 一个ATM机和A ...

  10. Entity Framework 6 Recipes 2nd Edition(11-5)译 - 从”模型定义”函数返回一个匿名类型...

    11-5. 从"模型定义"函数返回一个匿名类型 问题 想创建一个返回一个匿名类型的"模型定义"函数 解决方案 假设已有游客(Visitor) 预订(reserv ...

最新文章

  1. 2016年,你该如何在 Facebook 上做营销?
  2. Matlab符号计算结果过长无法在屏幕中显示的问题
  3. Android被逼学习例子2
  4. c语言推箱子文字说明,c语言 推箱子(C language Sokoban).doc
  5. Faceware 面部捕捉在Unity中的应用
  6. stotybord如何添加子视图_Revit软件技巧合集(建筑构件、视图处理、建筑表现、高级技巧)...
  7. 软件工程资料 - 优秀的大学怎么教程序开发和软件工程课
  8. 【R】OPPO发布惊人技术,这才是未来手机该有的样子啊!
  9. 利用jquery实现电商网站常用特效之:五星评分
  10. java集合框架的选用 若是数据量很大,0421测试题
  11. alienware灯光无法修改问题
  12. jQuery控制video视频(快进,回退,倍速播放等)
  13. CSS3表单设计–复古
  14. 用python玩3x3数字华容道
  15. 神器VIM配置文件进阶v1.0beta
  16. LCMS零件同步-字符串解析
  17. HTML:桂林山水风景Web界面设计
  18. Visual C++网络编程经典案例详解 第5章 网页浏览器 CHtmlView类 查看源文件
  19. 微信小程序和H5网页之间有什么区别?
  20. Linux socket accept尽信书不如无书

热门文章

  1. 计算机技术单科线,考研分数线怎么看,计算机专业的,国家线是什么 单科?...
  2. pytest的fixture传参数
  3. Java+Selenium3.0----------启动谷歌浏览器及错误处理
  4. mac obs 录屏黑屏_差点被录屏软件搞死.......
  5. c++ 如何将输入的内容输出到文本文件 要建立文本文件嘛_python如何学习
  6. linux vcenter6.5下载,vCenter 6.0更新至6.5
  7. c语言中嵌套循环的作用,C语言中n层循环嵌套实现
  8. 报错,> 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL
  9. 报错,void AcceptAndReadAvailableTracks(const QString param, int timeout)
  10. win7桌面图片不显示缩略图问题