1. 问题背景

在我的力推下,部门业务开发转向ABP,其中ORM采用的是EntityFrameworkCore.

然而,在数据查询方面,出现了重大的性能问题...

请看代码:

//在一个百万数据量的表中分页获取十条数据居然花了180ms左右,简直不能忍。
var entityList = await query
.PageBy(input)
//这是个字符串:MonthCode desc
.OrderBy(input.Sorting)
.ToListAsync();

这是很常见的Abp示例项目中的CURD中的常规代码,被大量使用...

2.分析问题

2.1 遇到问题先猜,提高查问题效率

开始我平淡的猜测...

a. 整段代码平淡无奇,【但是OrderBy的出现】直接解决了任意字段排序的问题,简直解放双手,要知道百万数据在前端排序是不可能的。

b. 【问题只能被转移,不能被消灭】 --我的编程思想

c. 所以,问题初步定在Orderby上。

2.2 猜到问题代码,继续猜可能的原因

a. 按下F12查看函数签名:

OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object[] args);

b. 开始感性的猜测,只需要一路F12即可。

1. IOderQueryable继承自IQueryable
2. IQueryable由:Type(类型),Expression(表达式树),Provider(表达式树的解析器)组成
3. Expression的构建需要涉及到元数据反射创建。
4. 反射!!!元数据!!!所以真相可能是:从SQL字符串,动态生成Expression!然后,创建IOrderQueryable,最后由EF的Provider解析出SQL,而不是简单的直接作为Orderby字符串拼接...

2.3 猜个大概了,开始证明它吧!

2.3.1 查看OrderBy源码

我用ILSpy反编译工具

public static IOrderedQueryable OrderBy(this IQueryable source, ParsingConfig config, string ordering, params object[] args)
{
Check.NotNull<IQueryable>(source, "source");
Check.NotEmpty(ordering, "ordering");
ParameterExpression[] parameters = new ParameterExpression[]
{
ParameterExpressionHelper.CreateParameterExpression(source.ElementType, string.Empty)
};
//果真String转Expression,还没有缓存,是快不起来了...
IEnumerable<DynamicOrdering> arg_48_0 = new ExpressionParser(parameters, ordering, args, config).ParseOrdering(false);
Expression expression = source.Expression;
foreach (DynamicOrdering current in arg_48_0)
{
expression = Expression.Call(typeof(Queryable), current.MethodName, new Type[]
{
source.ElementType,
current.Selector.Type
}, new Expression[]
{
expression,
Expression.Quote(Expression.Lambda(current.Selector, parameters))
});
}
Expression expression2 = DynamicQueryableExtensions.OptimizeExpression(expression);
return (IOrderedQueryable)source.Provider.CreateQuery(expression2);
}
2.3.2 初步结论:

为什么是初步结论呢,,,因为EF还有个二次缓存机制不是...热启动怎么也这么慢,是不是得查它

所以:OrderBy的时候,是由字符串,反射生成表达式树后,创建Queryable,交给EF做后续处理!所以,性能是快不起来的,这里性能大概就消耗了80ms左右!

2.3.3 开始查EntityFramework的缓存机制

其实这个阶段不用查...因为OrderBy每次都会执行生成Expression的过程,所以性能稳稳有问题,但是我真的好奇...

EFCore执行查询的源码

 public virtual TResult Execute<TResult>(Expression query)
{
Check.NotNull(query, nameof(query)); var queryContext = _queryContextFactory.Create(); query = ExtractParameters(query, queryContext, _logger);
//获取缓存的地方
var compiledQuery
= _compiledQueryCache
//这个query就是他的key.
.GetOrAddQuery(
_compiledQueryCacheKeyGenerator.GenerateCacheKey(query, async: false),
() => CompileQueryCore<TResult>(query, _queryModelGenerator, _database, _logger, _contextType)); return compiledQuery(queryContext);
}

看一下query的结构

结论:EF的缓存机制是用生成后的表达式树做的Key哦,但是生成表达式树的那段代码的性能损耗是无法避免的了!所以!!!慎用!!!动态SQL!!!

EF性能分析(一):动态SQL性能差.从OrderBy开始分析的更多相关文章

  1. Oracle DB SQL 性能分析器

    • 确定使用SQL 性能分析器的优点 • 描述SQL 性能分析器工作流阶段 • 使用SQL 性能分析器确定数据库更改所带来的性能改进 SQL 性能分析器:概览 • 11g 的新增功能 • 目标用户:D ...

  2. Oracle SQL 性能优化技巧

    Select语句完整的执行顺序: SQL Select语句完整的执行顺序: 1. from子句组装来自不同数据源的数据: 2.where子句基于指定的条件对记录行进行筛选: 3.group by子句将 ...

  3. 动态SQL使用小结

    1.什么是动态SQL? 静态 SQL:静态 SQL 语句一般用于嵌入式 SQL 应用中,在程序运行前,SQL 语句必须是确定的,例如 SQL 语句中涉及的列名和表名必须是存在的.静态 SQL 语句的编 ...

  4. sqlt 之 分析 DB upgrade 导致SQL 性能下降 的方法 xplore

    https://blog.csdn.net/lukeUnique/article/details/79331779 https://mauro-pagano.com/2014/10/27/when-t ...

  5. SQL性能优化案例分析

    这段时间做一个SQL性能优化的案例分析, 整理了一下过往的案例,发现一个比较有意思的,拿出来给大家分享. 这个项目是我在项目开展2期的时候才加入的, 之前一期是个金融内部信息门户, 里面有个功能是收集 ...

  6. SQL性能分析之执行计划

    一直想找一些关于SQL语句性能调试的权威参考,但是有参考未必就能够做好调试的工作.我深信实践中得到的经验是最珍贵的,书本知识只是一个引导.本篇来源于<Inside Microsoft SQL S ...

  7. 使用Oracle执行计划分析SQL性能

    执行计划:一条查询语句在ORACLE中的执行过程或访问路径的描述.即就是对一个查询任务,做出一份怎样去完成任务的详细方案. 如果要分析某条SQL的性能问题,通常我们要先看SQL的执行计划,看看SQL的 ...

  8. Mysql高级操作学习笔记:索引结构、树的区别、索引优缺点、创建索引原则(我们对哪种数据创建索引)、索引分类、Sql性能分析、索引使用、索引失效、索引设计原则

    Mysql高级操作 索引概述: 索引是高效获取数据的数据结构 索引结构: B+Tree() Hash(不支持范围查询,精准匹配效率极高) 树的区别: 二叉树:可能产生不平衡,顺序数据可能会出现链表结构 ...

  9. 使用show profiles分析SQL性能

    如何查看执行SQL的耗时 使用show profiles分析sql性能. Show profiles是5.0.37之后添加的,要想使用此功能,要确保版本在5.0.37之后. 查看数据库版本 mysql ...

随机推荐

  1. HDU 1253 胜利大逃亡 NYOJ 523【BFS】

    胜利大逃亡 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Subm ...

  2. MongoDB数据库设计中6条重要的经验法则

    Part 1 原文:6 Rules of Thumb for MongoDB Schema Design: Part 1 By William Zola, Lead Technical Support ...

  3. DataBase 之 拉链表结构设计

    一.概念 拉链表是针对数据仓库设计中表存储数据的方式而定义的,顾名思义,所谓拉链,就是记录历史.记录一个事物从开始,一直到当前状态的所有变化的信息. 在历史表中对客户的一生的记录可能就这样几条记录,避 ...

  4. [转]bing壁纸天天换 初识shell魅力

    原文链接:http://www.cnblogs.com/atskyline/p/3679522.html 原文的程序跑在window上,curl的使用不太一样,想要获取的图片也不太一样.修改后的代码如 ...

  5. UIImagePickerController 视频录制操作,视频大小,时间长度

    一:使用 iOS 系统 UIImagePickerController 获取视频大小 获取视频长度 - (void)viewDidLoad { [super viewDidLoad]; // Do a ...

  6. qs.stringify() 和JSON.stringify()的区别

    var a = {name:'hehe',age:10}; qs.stringify(a) // 'name=hehe&age=10' JSON.stringify(a) // '{" ...

  7. Linux打包解压

    tar tar命令可以用来压缩打包单文件.多个文件.单个目录.多个目录. 常用格式: 单个文件压缩打包: tar czvf my.tar file1 多个文件压缩打包: tar czvf my.tar ...

  8. PHP的session存储对PHP运行环境的影响

    转于:http://hmw.iteye.com/blog/1704020 这个问题的引入是由于公司一个项目里需要使用单点登录的功能,为了方便起见,就使用redis来替换php默认的文件存储sessio ...

  9. 智能指针tr1::shared_ptr、boost::shared_ptr使用

    对于tr1::shared_ptr在安装vs同一时候会自带安装,可是版本号较低的不存在.而boost作为tr1的实现品,包括 "Algorithms Broken Compiler Work ...

  10. Atitit.angular.js 使用最佳实践 原理与常见问题解决与列表显示案例 attilax总结

    Atitit.angular.js 使用最佳实践 原理与常见问题解决与列表显示案例 attilax总结 1. 本文范围 1 2. Angular的优点 1 2.1. 双向数据绑定 1 2.2. dsl ...