EF 剥坑
1、简单 count 会生成不必要的嵌套
var xs = (from x in dbContext.db_API_Operationallog where x.id<1 select 1 ).Count(); 结果: SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[db_API_Operationallog] AS [Extent1] WHERE [Extent1].[id] < 1 ) AS [GroupBy1]
2、查询某些列的时候会整个模型查询
context.db_API_Operationallog.FirstOrDefault(p => p.Id == postId).Hits; 或者: context.db_API_Operationallog.Find(postId).Hits;
会把整个post表数据都查出然后再内存里面找了hits这个列
优化:
context.db_API_Operationallog.Where(p => p.Id == postId).Select(p => p.Hits).FirstOrDefault();
3、不要轻易的把数据全部加载到内存
有时候一个不小心在查询的sql build 里面加了个tolist(), toArray()等,这种真正的执行了查询,这样在开发环境往往表的数据比较少,程序运行比较快,但是一到线上环境数据量比较大的情况下就会出现内存爆满的问题,这个问题相对来说比较隐蔽,所以开发的时候一定要小心。
4、IQueryable, IEnumerable
IEnumerable 执行的where 先是走内存,在走内存查询
public IEnumerable<db_API_Operationallog> GetAllPost() { return context.Post; } int id = 2000; var log = GetAllPost().Where(s => s.id <id).ToList();
Sql Server Profiler 抓到的信息
SELECT [Extent1].[id] AS [id], [Extent1].[uid] AS [uid], [Extent1].[types] AS [types], [Extent1].[events] AS [events], [Extent1].[more] AS [more], [Extent1].[money] AS [money], [Extent1].[lastmoney] AS [lastmoney], [Extent1].[nowmoney] AS [nowmoney], [Extent1].[bak] AS [bak], [Extent1].[times] AS [times] FROM [dbo].[db_API_Operationallog] AS [Extent1]
把上面的 IEnumerable 换成 IQueryable
exec sp_executesql N'SELECT [Extent1].[id] AS [id], [Extent1].[uid] AS [uid], [Extent1].[types] AS [types], [Extent1].[events] AS [events], [Extent1].[more] AS [more], [Extent1].[money] AS [money], [Extent1].[lastmoney] AS [lastmoney], [Extent1].[nowmoney] AS [nowmoney], [Extent1].[bak] AS [bak], [Extent1].[times] AS [times] FROM [dbo].[db_API_Operationallog] AS [Extent1] WHERE [Extent1].[id] < @p__linq__0',N'@p__linq__0 int',@p__linq__0=2000
这个坑是比较同样也是比较隐蔽的注意下
5、使用 NoTracking 降低 状态开销
dbContext.db_API_Operationallog.Where(s => s.id < id).AsNoTracking().ToList();
总结
平时写EF的时候一定要把脚步停下了 多使用 Sql Server Profiler 琢磨下自己的代码
无生,无灭,看似最高境界