原文:https://www.cnblogs.com/wangyuliang/p/10338902.html

     https://www.cnblogs.com/simadi/p/6879366.html

现在工作中很少使用原生的sql了,大多数的时候都在使用EF。刚开始的时候,只是在注重功能的实现,最近一段时间在做服务端接口开发。开发的时候也是像之前一样,键盘噼里啪啦的一顿敲,接口秒秒钟上线,但是到联调测试的时候就悲剧了。。。。那叫一个慢啊,客户端有种“千年等一回的赶脚” 。由于访问量和数量都提升了一个数量级,之前没有 考虑过的问题,都在此时暴露了,根据自己百度、google的经历实践,整理了这一些优化点。欢迎各位大神批评指正!

1.使用AsNoTracking(),无跟踪查询,查询出的数据不可以修改,但是可以提高查询速度

对于只读操作,强烈建议使用AsNoTracking进行数据获取,这样省去了访问EF Context的时间,会大大降低数据获取所需的时间。

同时由于没有受到上下文的跟踪缓存,因此取得的数据也是及时最新的,更利于某些对数据及时性要求高的数据查询。

db.Person.Where(a => a.IsDeleted == false).AsNoTracking().ToList();

2.合理使用延迟加载。

如果用不到导航属性中的数据,那么使用懒加载就行了,不会加载不需要的数据到内存中。但是,如果会在 foreach 中使用导航属性中的数据,那么最好是禁用懒加载,通过Include()方法,一次加载全部数据,防止在 foreach 多次和数据库进行交互。当然,一般情况下是这样的,具体的还是要根据当时的业务情况而定。

3.判断List中是否含有数据的时候,最好使用Any(),避免使用Count()>0,这么Low的方式,真是慢的一逼啊。

4.在where子句中进行中文字符模糊匹配值的时候,记得加上使用DbFunctions.AsNonUnicode("要匹配的字符")。

    var query = db.User.Where(a=>a.Name=="makmong").ToList();

修改后:var query = db.User.Where(a=>a.Name== DbFunctions.AsNonUnicode("makmong")).ToList();

5.错误的使用OrderBy() 导致的错误排序。

要对多个字段进行先后组合排序的时候,正确的是Orderby().ThenBy();切记不要这样啊:OrderBy().OrderBy(),这样达不到你想要的效果,只会按照最后的那个排序字段进行排序。

6.真假分页的问题

line1:query.ToList().Skip((PageIndex - 1) * PageSize).Take(PageSize);

line2: query.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList();

line1就是加分页,直接从DB中取出全部的数据,然后在内存中进行分页;line2才是真正分页。没有ToList()的时候,返回值类型还是IQueryable<T> ,执行了ToList(),之后直接查询数据库了,返回值类型直接是IEnumerable<T>。

7.按需加载部分列。

建议使用ViewModel代替实体Model

接着新建ViewModel

public class UserViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}

开始查询:

var query = db.User.Select(a=>new UserViewModel()
{
Id = a.Id,
Name = a.Name
}).ToList();

Model实体中枚举使用byte类型

我们先来了解下Sqlserver中tinyint, smallint, int, bigint的区别

  • bigint:从-263(-9223372036854775808)到263-1(9223372036854775807)的整型数据,存储大小为 8 个字节。一个字节就是8位,那么bigint就有64位

  • int:从-231(-2,147,483,648)到231-1(2,147,483,647)的整型数据,存储大小为 4 个字节。int类型,最大可以存储32位的数据

  • smallint:从-215(-32,768)到215-1(32,767)的整数数据,存储大小为 2 个字节。smallint就是有16位

tinyint:从0到255的整数数据,存储大小为 1 字节。tinyint就有8位。

所以对于有些范围比较短的数值长度,例如枚举类型值,完全可以使用byte类型替换int类型,对应生成数据库tinyint类型以节省数据存储。

如:

public CouponType CouponType { get; set; }
public enum CouponType : byte
{
RedBag = 0,
Experience = 1,
Cash = 2,
JiaXiQuan = 3
}

8.使用扩展库Entity Framework Extendeds 进行批量Insert和delete操作,避免生成大量的sql语句和数据库进行多次交互。

Nuget****安装 PM> Install-Package EntityFramework.Extended

9.这些做了,性能还是不行?那SqlQuery(),或者通过储存过程,将多条sql语句作为一个提交单元,也可以减少与数据库的交互次数,从而提高性能。

对于EF首次启动慢的问题,可通过下面的措施进行优化:

1.EF的预热问题,在应用程序进行初始化的时候就事先进行预热。比如,mvc应用程序可在global文件中添加如下操作。

protected void Application_Start()
{
using (var ctx = new mcccEntities())
{
var objectContext = ((IObjectContextAdapter)ctx).ObjectContext;
var mappingCollection = (StorageMappingItemCollection)objectContext.MetadataWorkspace.GetItemCollection(DataSpace.CSSpace);
mappingCollection.GenerateViews(new List<EdmSchemaError>());
} //记得,连接了几个DB就要写几个using啦。 }

EF使用SQL分库操作

当数据库的表及数据达到一定规模后我们想到的优化就有分库,分表之类的优化操作。

对于之前的ADO.NET来说分库是一件很普通的操作。

比如下面的非跨数据库查询语句:

SELECT Name FROM dbo.User WHERE ID=1

跨数据库查询语句:

SELECT Name FROM MaiMangAdb.dbo.blog_PostBody WHERE ID=1

我们知道EF的DbContext中已经指定了连接字符串

public EntityDB() : base("DefaultConnection")
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=.;Initial Catalog=EFStudy;Integrated Security=True;" providerName="System.Data.SqlClient" />
</connectionStrings>

也就是说所有的上下文操作都是基于这个数据库来操作的,那我们就不能用ADO.NET那套,多个查询配多个链接去操作数据库。

当然大神们也给出了一套方法,而且也是简单明了。那我也就直接将其移植过来记录一下吧。

方法就是给数据库添加SYNONYM 同义词,我在此演示下

创建2张Model表User和Role

public class User
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public bool IsDeleted { get; set; }
[DateTime2Precision]
public DateTime CreateDateTime { get; set; }
}
public class Role
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}

并添加一条语句:

EntityDB db = new EntityDB();
db.User.Add(new User { Id = 1, Name = "ddd" ,CreateDateTime = DateTime.Now});
db.Role.Add(new Role() {Id = 1, Name = "admin"});
db.SaveChanges();

运行查看数据库:

现在数据库表及内容都有了。然后我要把User表及内容移植到另一个数据库中,且不影响当前的EF操作。

创建新的数据库EFSYNONYM并添加User表,表结构和EFStudy中的User一致。

然后在EFStudy中删除表User且创建同义词

CREATE SYNONYM [dbo].[Users] FOR  [EFSYNONYM].[dbo].[Users]

此时的User和Role已经分别存在于不同的数据库里面,我们来插入查询数据操作下

至此分库成功。当然此方法也有个缺点就是分库表和主表间由同义词关联而无法建立主外键关系(其实当数据量达到一定级别后联合join查询反而不如分开多次查询来得快,

且由于在同一个上下文中,不用太过于关心由数据多次连接开关而产生影响,凡事有利弊总得有个最优是吧),因此我们可以把一些独立的容易过期的数据表给移植到单独的数据库,利于管理同时也利于优化查询。

C# EF优化的更多相关文章

  1. 记录一次EF优化

    问题描述:1.第一次加载过慢(EntityFramework 6 code-first).2.一段时间间不访问页面同样变慢. 原因分析:1.第一次启动(Code First)会对比程序中的Model与 ...

  2. EF优化之启动预热

    为什么Entity Framework的初始化速度慢如蜗牛呢? 对于在应用程序中定义的每个DbContext类型,在首次使用时,Entity Framework都会根据数据库中的信息在内存生成一个映射 ...

  3. SQL&EF优化第一篇 各种情况下的性能测试之count函数篇

    测试环境  mssql 08  +win7    数据 30W条 二〇一六年十月二十九日 09:04:43 结论:1>主键> *>可空列    推测未论证: 根据情况优先选择 顺便提 ...

  4. 优化EF Code First第一次请求速度

    由于EF Code First模式没有模型文件,所以很多一次请求的时候速度比较慢,EF需要将对应的数据库映射关系加载到内存里面,往后请求就比较快.可以通过在程序初始化的时候增加一段代码来优化EF第一次 ...

  5. EntityFramework使用及优化

    1. 简介 ORM框架:Object Relation Mapping,用操作对象的方式来操作数据库 其它框架:Dapper.NHibernate,首推EF,微软官方的. EF底层还是ADO.NET实 ...

  6. EntityFramework中对象的状态管理(笔记)

    刚开始接触EF框架的时候总是不明白: 为什么查询出来的对象 Remove().再 SaveChanges()就会把数据删除.而自己 new 一个Person()对象,然后 Remove()不行? 为什 ...

  7. 如鹏网学习笔记(十五)ASP.NET MVC核心基础笔记

    一.ASP.Net MVC简介 1,什么是ASP.NET MVC? HttpHandler是ASP.net的底层机制,如果直接使用HttpHandler进行开发难度比较大.工作量大.因此提供了ASP. ...

  8. 数据迁移最快方式,多线程并行执行 Sql插入

    前言: 由于系统升级,新开发的系统对数据验证,及数据关联做了很多优化,现需要将原历史版本的数据迁移到新系统中:原数据库大约有 1千多万数据,大约 50个表. 历史数据库命名为:A. 新系统库暂命名为 ...

  9. EntityFramework介绍

    首先我们说明一下ORM是什么. 微软官方提供的ORM工具,ORM让开发人员节省数据库访问的代码时间,将更多的时间放到业务逻辑层代码上.开发人员使用Linq语言,对数据库操作如同操作Object对象 一 ...

随机推荐

  1. php----等比缩放图片

    <?php /** * Created by PhpStorm. * User: admin * Date: 2019/11/19 * Time: 8:54 */ $filename = 'lo ...

  2. eclips 中的 svn 更新报错,被锁住解决办法

    svn更新不下来,在文件的目录上选择 Team,然后选择 Refresh/Cleanup ,然后就可以了,这个方法我自己试有效,做为参考,对其它情况不一定有效 报错如下 解决方法

  3. 用TweenMax.js动画让数字动起来

    html: <div class="val2">0</div> js: let val2 = document.getElementsByClassName ...

  4. React Native 之TouchableOpacity组件

    使用TouchableOpacity组件 实现单击事件只需要声明onPress属性即可,其他同理,实现onPressIn,onPressOut,onLongPress constructor(prop ...

  5. React Native 之FlatList

    1.新建项目 2.因为要用到导航跳转, 所以添加依赖,,这里拷贝这个: "dependencies": { "@types/react": "^16. ...

  6. pages

    pages pages 接受一个数组,每一项都是一个字符串,指定 SWAN App 都有哪些页面.每一项代表页面的[路径 + 文件名],数组第一项代表 SWAN 初始页面. SWAN 中新增或减少页面 ...

  7. 【bzoj3295】[Cqoi2011]动态逆序对

    题目描述: 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆 ...

  8. php 客户端调用elasticsearch接口

    1.php调用elasticsearch接口[参考资料:https://www.cnblogs.com/php0916/articles/6587340.html] /data/www/syhuo.n ...

  9. fengmiantu3

  10. oracle DBID,SID,DB_NAME,DB_DOMAIN,INSTANCE_NAME,DB_UNIQUE_NAME, SERVICE_NAMES 及监听参数的说明

    DBID,SID,DB_NAME,DB_DOMAIN,INSTANCE_NAME,DB_UNIQUE_NAME, SERVICE_NAMES 及监听参数的说明 DB 相关的: DBID, SIDPFI ...