问题

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

解决方案

假设你有如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 译 -> 目录 -持续更新

    因为看了<Entity Framework 6 Recipes 2nd Edition>这本书前面8章的翻译,感谢china_fucan. 从第九章开始,我是边看边译的,没有通读,加之英语 ...

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

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

  3. Entity Framework 6 Recipes 2nd Edition(9-3)译->找出Web API中发生了什么变化

    9-3. 找出Web API中发生了什么变化 问题 想通过基于REST的Web API服务对数据库进行插入,删除和修改对象图,而不必为每个实体类编写单独的更新方法. 此外, 用EF6的Code Fri ...

  4. Entity Framework 6 Recipes 2nd Edition(9-4)译->Web API 的客户端实现修改跟踪

    9-4. Web API 的客户端实现修改跟踪 问题 我们想通过客户端更新实体类,调用基于REST的Web API 服务实现把一个对象图的插入.删除和修改等数据库操作.此外, 我们想通过EF6的Cod ...

  5. Entity Framework 6 Recipes 2nd Edition(11-11)译 -> 在LINQ中调用数据库函数

    11-11. 在LINQ中调用数据库函数 问题 相要在一个LINQ 查询中调用数据库函数. 解决方案 假设有一个任命(Appointment )实体模型,如Figure 11-11.所示, 我们想要查 ...

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

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

  7. Entity Framework 6 Recipes 2nd Edition(13-3)译 -> 为一个只读的访问获取实体

    问题 你想有效地获取只是用来显示不会更新的操作的实体.另外,你想用CodeFirst的方式来实现 解决方案 一个非常常见行为,尤其是网站,就是只是让用户浏览数据.大多数情况下,用户不会更新数据.在这种 ...

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

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

  9. Entity Framework 6 Recipes 2nd Edition(13-5)译 -> 使POCO的修改追踪更高

    问题 你正在使用POCO,你想提高修改跟踪的性能,同时使内存消耗更少.另外,你想通过EF的CodeFirst方式来实现. 解决方案 假设你有一个关于Account(帐户)和相关的Payments(支付 ...

  10. Entity Framework 6 Recipes 2nd Edition(13-9)译 -> 避免Include

    问题 你想不用Include()方法,立即加载一下相关的集合,并想通过EF的CodeFirst方式实现. 解决方案 假设你有一个如Figure 13-14所示的模型: Figure 13-14. A ...

随机推荐

  1. JavaScript 对象属性介绍

    本篇主要介绍JS中对象的属性,包括:属性的分类.访问方式.检测属性.遍历属性以及属性特性等内容. 目录 1. 介绍:描述属性的命名方式.查找路径以及分类 2. 属性的访问方式:介绍'.'访问方式.'[ ...

  2. HTML骨架结构

    前面的话   一个完整的HTML文档必须包含3个部分:文档声明.文档头部和文档主体.而正是它们构成了HTML的骨架结构.前面已经分别介绍过文档声明和文档头部,本文将详细介绍构成HTML骨架结构的基础元 ...

  3. dubbo服务提供与消费

    一.前言 项目中用到了Dubbo,临时抱大腿,学习了dubbo的简单实用方法.现在就来总结一下dubbo如何提供服务,如何消费服务,并做了一个简单的demo作为参考. 二.Dubbo是什么 Dubbo ...

  4. 玩转spring boot——开篇

    很久没写博客了,而这一转眼就是7年.这段时间并不是我没学习东西,而是园友们的技术提高的非常快,这反而让我不知道该写些什么.我做程序已经有十几年之久了,可以说是彻彻底底的“程序老炮”,至于技术怎么样?我 ...

  5. VSCode调试go语言出现:exec: "gcc": executable file not found in %PATH%

    1.问题描述 由于安装VS15 Preview 5,搞的系统由重新安装一次:在用vscdoe编译go语言时,出现以下问题: # odbcexec: "gcc": executabl ...

  6. DDD领域驱动设计 - 设计文档模板

    设计文档模板: 系统背景和定位 业务需求描述 系统用例图 关键业务流程图 领域语言整理,主要是整理领域中的各种术语的定义,名词解释 领域划分(分析出子域.核心域.支撑域) 每个子域的领域模型设计(实体 ...

  7. webix前端架构的项目应用

    webix框架兼容javascript.HTML.CSS,应用比较灵活,应用框架时,配合后台webAPI,整个web项目里面,App文件夹保存前台的多语言文件,图片文件,webix原代码js.css, ...

  8. 【SAP业务模式】之ICS(一):业务详述

    PS:本专题系列讲述如何在SAP系统中实现ICS的业务模式,本系列博文系原创,如要转载引用,请保持原文一致并注明出处! SAP系统自身功能非常强大,支持多种业务模式,通过前台后台的配置就可以实现多种效 ...

  9. BRDF 光照模型

    http://blog.csdn.net/liu_lin_xm/article/details/4846144

  10. 深入浅出聊优化:从Draw Calls到GC

    前言: 刚开始写这篇文章的时候选了一个很土的题目...<Unity3D优化全解析>.因为这是一篇临时起意才写的文章,而且陈述的都是既有的事实,因而给自己“文(dou)学(bi)”加工留下的 ...