-
1.对象的创建
1.1. 避免不必要的对象创建;
由于垃圾回收的代价较高,所以C#程序开发要遵循的一个基本原则就是避免不必要的对象创建
1.2. 避免循环创建对象;
如果对象并不会随每次循环而改变状态,那么在循环中反复创建对象将带来性能损耗。高效的做法是将对象提到循环外面创建
1.3. 在对应的逻辑分支创建对象;
如果对象只在某些逻辑分支中才被用到,那么应只在该逻辑分支中创建对象
1.4. 避免常量创建对象;
1.4.1 如下例,程序中存在大量 new decimal(0)的代码,这会导致小对象频繁创建及回收;正确的做法是使用 Decimal.Zero 常量
decimal _qtzf = new decimal(0);//其他支付
decimal _zje = new decimal(0);//总金额
decimal _zhzf = new decimal(0);//账户支付
decimal _tczf = new decimal(0);//统筹支付
decimal _xjzf = new decimal(0);//现金支付2 .string与stringBuilder的合理使用
如下例, String 是不变类,使用 + 操作连接字符串将会导致创建一个新的字符串。如果字符串连接次数不是固定的,会导致创建一个新的空间来存储连接后的字符串,在多次循环中使用“+”会导致内存循环被开辟。例如在一个循环中,则应该使用 StringBuilder 类来做字符串连接工作。因为 StringBuilder 内部有一个 StringBuffer ,连接操作不会每次分配新的字符串空间
var strSFXMMCs=“”;
strSFXMMCs = strSFXMMCs + "大病支付 " + (printObject.DBZFJE ?? "0") + "<br />";
strSFXMMCs = strSFXMMCs + "医疗救助 " + (printObject.JZJJZF ?? "0") + "<br />";
strSFXMMCs = strSFXMMCs + "补充医疗 " + (printObject.GRBCJJZF ?? "0") + "<br />";
strSFXMMCs = strSFXMMCs + "账户余额 " + (printObject.ZHYE ?? "0") + "<br />";
strSFXMMCs = strSFXMMCs + "公务 员 " + (printObject.GWYBZYLBZJJ ?? "0") + "<br />";
strSFXMMCs = strSFXMMCs + "伤残医保 " + (printObject.SCRYYLBZJJ ?? "0") + "<br />";
strSFXMMCs = strSFXMMCs + "其他基金 " + (printObject.QTJJ ?? "0") + "<br />";
strSFXMMCs = strSFXMMCs + "低保救助 " + (printObject.DBJZJEZF ?? "0") + "<br />";3.代码对象非空判断
如下例,
pi.SFXZMC = objSFXZ.FirstOrDefault(a => a.SFXZBM == pi.SFXZBM).MC;
正确写法
if (objSFXZ != null)
pi.SFXZMC = objSFXZ.FirstOrDefault(a => a.SFXZBM == pi.SFXZBM)?.MC;5.EF注意事项 中使用 AsNoTracking,Any,AsParallel,Aggregate
EF.Functions.Like(p.Name,"%燕%") 替换 EF.Contains(“燕“)
1.使用最新版的EF
2. 禁用延迟加载
3.使用贪婪加载(又叫预加载就是数据库的多表查询)
4.了解 ToList(), .AsEnumerable(), AsQueryable() 的区别4.1 AsEnumerable()延迟执行,不会立即执行。当你调用.AsEnumerable()的时候,实际上什么都没有发生。
4.2 .ToList()立即执行.当你需要操作结果的时候,用.ToList(),否则,如果仅仅是用来查询不需要进一步使用结果集,并可以延迟执行,就用.AsEnumerable()/IEnumerable /IQueryable
4.3. AsEnumerable()虽然延迟执行,但还是访问数据库,而.ToList()直接取得结果放在内存中。比如我们需要显示两个部门的员工时,部门可以先取出放置在List中,然后再依次取出各个部门的员工,这时访问的效率要高一些,因为不需要每次都访问数据库去取出部门。
4.4 IQueryable实现了IEnumberable接口。但IEnumerable<T> 换成IQueryable<T>后速度提高很多。原因:
IQueryable接口与IEnumberable接口的区别: IEnumerable<T> 泛型类在调用自己的SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,而IQueryable<T> 是将Skip ,take 这些方法表达式翻译成T-SQL语句之后再向SQL服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。
4.5 IEnumerable跑的是Linq to Object,强制从数据库中读取所有数据到内存先5.优化操作AsNoTracking()
5.1.目前EF版本是6.0,生成的数据库实体模型都是DbSet<T>类型
5.2.默认情况下对于数据的访问都是启用模型跟踪
针对只读操作,强烈建议使用AsNoTracking进行数据获取,这样省去了访问EF Context的时间,会大大降低数据获取所需的时间。
同时由于没有受到上下文的跟踪缓存,因此取得的数据也是及时最新的,更利于某些对数据及时性要求高的数据查询
6.EF使用SqlQuery7.关于AsNonUnicode
var query = db.User.Where(a=>a.Name== DbFunctions.AsNonUnicode("mongo"))
生成 sql: select * from user where Name=N'mongo';
都知道N是将字符串作为Unicode格式进行存储。因为.Net字符串是Unicode格式,在SQL中Where子句中当一侧有N型而另一侧没有N型时,此时会进行数据转换,也就是说如果你在表中建立了索引此时会失效代替的是造成全表扫描。用 EntityFunctions.AsNonUnicode 方法来告诉.Net 将其作为一个非Unicode来对待,此时生成的SQL语句两侧都没有N型,就不会进行更多的数据转换,也就是说不会造成更多的全表扫描。所以当有大量数据时如果不进行转换会造成意想不到的结果,因此在进行字符串查找或者比较时建议用AsNonUnicode()方法来提高查询性能
8.关于Any
说明:用于判断集合中是否有元素满足某一条件;不延迟。(若条件为空,则集合只要不为空就返回True,否则为False)。有2种形式,分别为简单形式和带条件形式
p.TYBZ = ret.Where(_ => _.TYBZ == 0).ToList().Count > 0 ? 0 : 1;
优化后:
p.TYBZ = ret.Any(_ => _.TYBZ == 0) ? 0 : 1;9.关于AsParallel,Aggregate
10.建议使用ViewModel代替实体Model
查询的字段减少 (可能就几个) 对查询性能
11.合理使用EF扩展库12.批量查询功能
13.查询缓存功能
我们现在的后台项目权限管理模块,所有的菜单项都是写进数据库里,不同的角色用户所获取展示的菜单项各不相同。
项目导航菜单就是频繁的访问数据库导致性能低下(一开始得到1级菜单,然后通过1级获取2级菜单,2级获取3级)
解决方法就是第一次查询后把数据给缓存起来设定缓存时间,然后一段时间继续查询此数据(譬如整个页面刷新)则直接在缓存中获取,从而减少与数据库的交互。
代码如下:
var users = db.User.Where(u => u.Id > 5).FromCache(CachePolicy.WithDurationExpiration(TimeSpan.FromSeconds(30)));
如果在30秒内重复查询,则会从缓存中读取,不会查询数据库
14.分清真分页和假分页
如下例:
query.ToList().Skip((PageIndex - 1) * PageSize).Take(PageSize);
query.Skip((PageIndex - 1) * PageSize).Take(PageSize).ToList();
15.注意事务的简短性
在使用事务时,我们尽量要把与事务无关的东西放到事务外执行,比如(查询语句或者其他事务外的语句),
如果让一个事务的执行时间过长,很容易引起资源死锁的问题,当用压力测时,马上就出现资源被锁的错误