linq 大数据 sql 查询及分页优化
前提:
需要nuget PredicateLib 0.0.5;
SqlServer 2008R2 (建议安装 64 位);
.net 4.5 或以上;
当前电脑配置: I7 4核 3.6GHZ,8G 内存 (办公电脑 ,win10 64位)
描述:
在实际项目中我们会遇到多个表关联查询数据,并进行分页操作;当数据量很大的时候如(500万或以上)的时候,分页很吃力,特别还需要一些模糊查询,排序的时候会导致很慢;
本文章主要解决分页及多个数据表关系查询速度慢的问题:
解决办法及优化过程:
1、通常我们对 数据库的优化莫过于索引,储存过程等;
2、能使用一条Sql 语句查询的话,不要使用多条语句(学习使用 linq 语法);
3、尽量少使用 in ('.....') 多个值;经测试超过 5万个 in 的时候会提示内存不足异常;
4、order 的使用很是奇葩,原本用 order Id(主键),反而查询非常慢,而且 Cpu 使用一下子 100%,换成别的字段就完全没压力;(暂时无法理解,在出现问题后可尝试改变 order)
5、尽量 select 少的字段,在实际中遇到 分页的时候,先 select 出 Id,然后在通过 Id 去查询完整数据,会比直接查询完整要快 N 倍;
如通过两条语句查询出大数据的时候:var ids = select top 10 Id from ViewTable;
var datas = select * from ViewTable where Id in (ids);
结合表示式生成分页查询扩展(完美优化):
非常实用的硬代码,在大数据分页的时候性能优越:
主要原理跟上面 第 5点 一样,但优化只通过一次查询出完整数据;
缺点: 每页的数据量建议不要太大,比如:每页1万
/// <summary> /// 执行分页 /// 性能比较好 /// </summary> /// <typeparam name="T">实体类型<peparam> /// <param name="source">数据源</param> /// <param name="orderBy">排序字符串</param> /// <param name="pageIndex">分页索引</param> /// <param name="pageSize">分页大小</param> /// <param name="idSelector">Id选择器</param> /// <returns></returns> public static async Task<PageInfo<T>> ToPageAsync<T, TId>(this IQueryable<T> source, string orderBy, int pageIndex, int pageSize, Expression<Func<T, TId>> idSelector) where T : class where TId : class { source = source.Where(Predicate.Create(idSelector, null, Operator.NotEqual)); int total = await source.CountAsync(); var inc = total % pageSize > 0 ? 0 : -1; var maxPageIndex = (int)Math.Floor((double)total / pageSize) + inc; pageIndex = Math.Max(0, Math.Min(pageIndex, maxPageIndex)); var idQuery = source.OrderBy(orderBy).Skip(pageIndex * pageSize).Take(pageSize).Select(idSelector); var datas = await source.Join(idQuery, idSelector, item => item, (item, id) => item).OrderBy(orderBy).ToArrayAsync(); var page = new PageInfo<T>(total, datas) { PageIndex = pageIndex, PageSize = pageSize }; return page; }