ASP.NET MVC + EF 利用存储过程读取大数据,1亿数据测试很OK
看到本文的标题,相信你会忍不住进来看看!
没错,本文要讲的就是这个重量级的东西,这个不仅仅支持单表查询,更能支持连接查询,
加入一个表10W数据,另一个表也是10万数据,当你用linq建立一个连接查询然后利用take,skip读取第N页数据的时候,
你的程序就挂了,因为,你很可能读取需要几十秒甚至几分钟以上。
下面来讲解一下,ASP.NET MVC + EF 利用存储过程读取大数据的详细过程。
1.首先,我们创建一个实体类PageinationInfo,主要用于分页,如下
- public class PageinationInfo
- {
- /// <summary>
- /// 要显示的表或多个表的连接
- /// </summary>
- public string strTable { get; set; }
- /// <summary>
- /// 要查询的字段
- /// </summary>
- public string strField { get; set; }
- /// <summary>
- /// 每页多少条记录
- /// </summary>
- public int pageSize { get; set; }
- /// <summary>
- /// 当前页
- /// </summary>
- public int pageIndex { get; set; }
- /// <summary>
- /// 查询条件,不需where
- /// </summary>
- public string strWhere { get; set; }
- /// <summary>
- /// 用于排序的主键
- /// </summary>
- public string strSortKey { get; set; }
- /// <summary>
- /// 用于排序,如:id desc (多个id desc,dt asc)
- /// </summary>
- public string strSortField { get; set; }
- /// <summary>
- /// 排序,0-顺序,1-倒序
- /// </summary>
- public bool strOrderBy { get; set; }
- /// <summary>
- /// 总记录数
- /// </summary>
- public int RecordCount { get; set; }
- /// <summary>
- /// 总页数
- /// </summary>
- public int PageCount { get; set; }
- /// <summary>
- /// 查询耗时,毫秒为单位
- /// </summary>
- public int UsedTime { get; set; }
- }
2.然后我们再DAL层新建一个类 PageinationInfoService 主要用于实现分页读取数据,如下:
- public class PageinationInfoService
- {
- /// <summary>
- /// 获取分页列表
- /// </summary>
- /// <param name="pageinationInfo"></param>
- /// <returns></returns>
- public IList<Entity> GetPageinationInfoList<Entity>(PageinationInfo pageinationInfo) where Entity : class
- {
- dynamic result = null;
- using (SnsLearningLogManagerDB db = new SnsLearningLogManagerDB())
- {
- #region SqlParameter参数
- SqlParameter[] paras = new SqlParameter[];
- paras[] = new SqlParameter("strTable", DbType.String);
- paras[].Value = pageinationInfo.strTable;
- paras[] = new SqlParameter("strField", DbType.String);
- paras[].Value = pageinationInfo.strField;
- paras[] = new SqlParameter("pageSize", DbType.Int16);
- paras[].Value = pageinationInfo.pageSize;
- paras[] = new SqlParameter("pageIndex", DbType.Int16);
- paras[].Value = pageinationInfo.pageIndex;
- paras[] = new SqlParameter("strWhere", DbType.String);
- paras[].Value = pageinationInfo.strWhere;
- paras[] = new SqlParameter("strSortKey", DbType.String);
- paras[].Value = pageinationInfo.strSortKey;
- paras[] = new SqlParameter("strSortField", DbType.String);
- paras[].Value = pageinationInfo.strSortField;
- paras[] = new SqlParameter("strOrderBy", DbType.Boolean);
- paras[].Value = pageinationInfo.strOrderBy;
- paras[] = new SqlParameter("RecordCount", DbType.Int16);
- paras[].Value = pageinationInfo.RecordCount;
- paras[].Direction = ParameterDirection.Output;
- paras[] = new SqlParameter("UsedTime", DbType.Int16);
- paras[].Value = pageinationInfo.UsedTime;
- paras[].Direction = ParameterDirection.Output;
- #endregion
- try
- {
- result = db.Database.SqlQuery<Entity>("exec LYBPager @strTable,@strField,@pageSize,@pageIndex,@strWhere,@strSortKey,@strSortField,@strOrderBy,@RecordCount output,@UsedTime output", paras).ToList();
- pageinationInfo.RecordCount = (int)paras[].Value;
- pageinationInfo.UsedTime = (int)paras[].Value;
- }
- catch (Exception ex)
- {
- throw;
- }
- }
- return result;
- }
- }
- PageinationInfoService类中我们传入的参数是实体和PageinationInfo,实体主要是用于接收数据并封装到实体中,LYBPager 这个是数据库中存储过程的名称,而UsedTime 就是存储过程读取数据所用的时间
- BLL层的东西,我就不贴出来了,你们或者用工厂模式或者用简单3层,这个都无关紧要。
- 3.接下来,我们在Controller里来处理我们的业务需求,贴一段自己项目的代码作为分析,如下
- public ActionResult Index(string LabelName,string _Title,string _Content, int pageNumber = , int pageSize = )
- {
- #region 分页
- SnsModels.PageinationInfo pageinationInfo = new SnsModels.PageinationInfo();
- pageinationInfo.pageIndex = pageNumber;
- pageinationInfo.pageSize = pageSize;
- pageinationInfo.RecordCount = ;
- pageinationInfo.strField = "*";
- pageinationInfo.strOrderBy = true;
- pageinationInfo.strSortField = "ArticleID desc";
- pageinationInfo.strSortKey = "ArticleID";
- pageinationInfo.strTable = "ArticleInfo";
- pageinationInfo.strWhere = " 1=1";
- pageinationInfo.UsedTime = ;
- pageinationInfo.PageCount = ;
- #endregion
- IList<SnsModels.LabelInfo> LabelInfoList = Repository.GetList<SnsModels.LabelInfo>();
- ViewBag.LabelInfoList = new SelectList(LabelInfoList,"LabelName","LabelName");
- #region 参数处理
- if (LabelName != null)
- {
- if (!string.IsNullOrEmpty(LabelName))
- {
- pageinationInfo.strWhere += " and LabelName like '%" + HttpUtility.UrlDecode(LabelName.Trim()) + "%'";
- ViewBag.LabelInfoList = new SelectList(LabelInfoList, "LabelName", "LabelName",LabelName.Trim());
- }
- }
- if (_Title != null)
- {
- if (!string.IsNullOrEmpty(_Title))
- {
- pageinationInfo.strWhere += " and Title like '%" + _Title.Trim() + "%'";
- }
- }
- if (_Content != null)
- {
- if (!string.IsNullOrEmpty(_Content))
- {
- pageinationInfo.strWhere += " and Content like '%" + _Content.Trim() + "%'";
- }
- }
- #endregion
- IList<SnsModels.ArticleInfo> List = PageinationInfoManager.GetPageinationInfoList<SnsModels.ArticleInfo>(pageinationInfo);
- #region 传值
- ViewBag.List = List;
- ViewBag.pageNumber = pageNumber;
- ViewBag.pageSize = pageSize;
- ViewBag.RecordCount = pageinationInfo.RecordCount;
- ViewBag.LabelName =HttpUtility.UrlDecode(LabelName);
- ViewBag._Title = _Title;
- ViewBag._Content = _Content;
- #endregion
- return View();
- }
上面我们通过把参数传递到PageinationInfo,然后根据传递的参数拼凑pageinationInfo.strWhere现实了多条件查询,
pageNumber,pageSize 我们已经传递到View,你可以通过Jquery插件展示你的分页,点击一下一页的时候,跳转回控制器就行了。
4,接下来,我给出存储过程,代码如下:
- USE [LearningLogManagerDB2]
- GO
- /****** Object: StoredProcedure [dbo].[LYBPager] Script Date: 07/30/2014 11:51:44 ******/
- SET ANSI_NULLS ON
- GO
- SET QUOTED_IDENTIFIER ON
- GO
- --参数说明-------------------------------------------------------------
- /**//*
- @strTable --要显示的表或多个表的连接
- @strField --要查询出的字段列表,*表示全部字段
- @pageSize --每页显示的记录个数
- @pageIndex --要显示那一页的记录
- @strWhere --查询条件,不需where
- @strSortKey --用于排序的主键
- @strSortField --用于排序,如:id desc (多个id desc,dt asc)
- @strOrderBy --排序,0-顺序,1-倒序
- @RecordCount --查询到的总记录数
- @UsedTime --耗时测试时间差
- */
- ALTER PROCEDURE [dbo].[LYBPager]
- @strTable varchar() = '[dbo].[ttable]',--表名
- @strField varchar() = '*', --查询字段
- @pageSize int = , --每页多少条记录
- @pageIndex int = , --当前页
- @strWhere varchar() = '1=1', --查询条件
- @strSortKey varchar() = 'id', --主键
- @strSortField varchar() = 'id DESC', --排序
- @strOrderBy bit = , --是否排序 1表示排序
- @RecordCount int OUTPUT, --总记录数
- @UsedTime int OUTPUT --查询耗时,毫秒为单位
- AS
- SET NOCOUNT ON
- Declare @sqlcount INT
- Declare @timediff DATETIME
- select @timediff=getdate()
- Begin Tran
- DECLARE @sql nvarchar(),@where1 varchar(),@where2 varchar()
- IF @strWhere is null or rtrim(@strWhere)=''
- BEGIN--没有查询条件
- SET @where1=' WHERE '
- SET @where2=' '
- END
- ELSE
- BEGIN--有查询条件
- SET @where1=' WHERE ('+@strWhere+') AND ' --本来有条件再加上此条件
- SET @where2=' WHERE ('+@strWhere+') ' --原本没有条件而加上此条件
- END
- --SET @sql='SELECT @intResult=COUNT(*) FROM '+@strTable+@where2
- BEGIN
- SET @sql='SELECT @sqlcount=COUNT(*) FROM (select '+@strSortKey+' from '+ @strTable + @where2 +') As tmptab'
- END
- --print @sql
- EXEC sp_executesql @sql,N'@sqlcount int OUTPUT',@sqlcount OUTPUT --计算总记录数
- SELECT @RecordCount = @sqlcount --设置总记录数
- IF @pageIndex= --第一页
- BEGIN
- SET @sql='SELECT TOP '+CAST(@pageSize AS varchar())+' '+@strField+' FROM '+@strTable+@where2+'ORDER BY '+ @strSortField
- END
- Else
- BEGIN
- IF @strOrderBy=
- SET @sql='SELECT TOP '+CAST(@pageSize AS varchar())+' '+@strField+ ' FROM '+
- @strTable+@where1+@strSortKey+'>(SELECT MAX('+case when charindex('.',@strSortKey)> then right(@strSortKey,len(@strSortKey)-charindex('.',@strSortKey)) else @strSortKey end+') '+ ' FROM (SELECT TOP '+
- CAST(@pageSize*(@pageIndex-) AS varchar())+' '+@strSortKey+' FROM '+@strTable+@where2+
- 'ORDER BY '+@strSortField+') t) ORDER BY '+@strSortField
- ELSE
- SET @sql='SELECT TOP '+CAST(@pageSize AS varchar())+' '+@strField+' FROM '+@strTable+@where1+
- @strSortKey+'<(SELECT MIN('+case when charindex('.',@strSortKey)> then right(@strSortKey,len(@strSortKey)-charindex('.',@strSortKey)) else @strSortKey end+') '+ ' FROM (SELECT TOP '+CAST(@pageSize*(@pageIndex-) AS varchar())+' '+
- @strSortKey+' FROM '+@strTable+@where2+'ORDER BY '+@strSortField+') t) ORDER BY '+@strSortField+''
- END
- print @sql
- --select @RecordCount
- EXEC(@sql)
- print @sql
- If @@Error <>
- Begin
- RollBack Tran
- Return -
- End
- Else
- Begin
- Commit TRAN
- set @UsedTime = datediff(ms,@timediff,getdate())
- --select @UsedTime
- --select datediff(ms,@timediff,getdate()) as 耗时
- Return @sqlcount
- End
当然存储过程不是本人写的,我只是利用而已,也用了很久了,感觉还可以,有兴趣的可以分析分析。
在此非常感谢很多博友加入本人ASP.NET MVC QQ群,并且都很踊跃提问。
本群提供ASP.NET MVC,EF,LINQ,WEB API技术支持,不在乎人多,在乎人精。
ASP.NET MVC群 171560784
诚邀各路高手、初学者加入。
ASP.NET MVC + EF 利用存储过程读取大数据,1亿数据测试很OK的更多相关文章
- ASP.NET MVC + EF 利用存储过程读取大数据
ASP.NET MVC + EF 利用存储过程读取大数据,1亿数据测试很OK 看到本文的标题,相信你会忍不住进来看看! 没错,本文要讲的就是这个重量级的东西,这个不仅仅支持单表查询,更能支持连接查询, ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(24)-权限组的设计和实现(附源码)(终结)
ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 (2):数据库访问层的设计Demo (3):面向接口编程 (4 ):业务逻辑层的封装 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列
http://www.cnblogs.com/hanyinglong/archive/2013/03/22/2976478.html ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(9)-TT模板的学习
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(9)-TT模板的学习 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 (2): ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(1)-框架搭建
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(1)-框架搭建 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) 前言:这篇博客开始我们便一步一步的来实现这 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开篇
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开篇 前言:博客又有一段时间没有更新了,心里感觉这段时间空空的,好像什么都没有学下,所以就想写博客,所以就有了这个系列,这里当然也 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(23)-设置角色遗留问题和为权限设置角色以及EasyUI Tabs的使用
ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框架搭建 (2):数据库访问层的设计Demo (3):面向接口编程 (4 ):业务逻辑层的封装 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(21)-用户角色权限基本的实现说明
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(21)-用户角色权限基本的实现说明 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框 ...
随机推荐
- LeetCode39 Combination Sum
题目: Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C ...
- flume监控之ganglia
对于日志来说,我觉得监控意义不大,因为写的速度一般不会特别快,但是如果是spooldir source,里面一小时放入十几G的数据让flume解析,特别是在结合kafka或者其他框架的话,监控就显得重 ...
- 1.5.7 CharFilterFactories
CharFilterFactories 字符过滤器是一个预处理输入字符的组件,字符过滤器可以链接如token过滤器,并放置在Tokenizer(分词器)的前面,字符过滤器可以添加,更改或删除字符,同时 ...
- 采用handle消息机制实现轮播效果
// 自动轮播条显示 if (mhandle == null) { mhandle = new Handler() { public void handleMessage(Message mes) { ...
- 用bootstrapValidator来验证UEditor
我们的项目使用了bootstrapValidator来作为前端校验,但是表单里面有一个UEditor,它用bootstrapValidator是没有效果的,为了页面风格统一,只好修修改改咯 首先来看一 ...
- 通用权限底层研究:Web应用限制IP访问的功能实现
如果你的web应用受到恶意扫描或攻击,你会怎么处理呢?大多数时候从应用日志里可以看到恶意扫描或攻击,遇到此类情况,如有一个可以进行IP访问控制的功能就好些了. 现将在MVC下实现的一个IP访问限制功能 ...
- iOS之block块
Block块. 1.声明Block int (^myBlock)(int n) = ^(int num) 类型 (^名称)(需要传的参数)= ^(参数) 2 __block 变量 在block块中修改 ...
- 从敏捷开发到小团队SVN
一.敏捷之惑 敏捷开发,有一个很好的实践,“每天都可以产生一个可用于发布的版本”. 以前对这句话感到非常的困惑,因为我们手中的项目是残缺的,基本只是程序的一个功能片段,在未集成之前如何发布得了?当然这 ...
- date & dirname
date 年:+%Y 月:+%m 日:+%d 时:+%H 或者 +%k 分:+%M 秒:+%S 周:+%w dirname 目录 获取目录的上级目录
- [wordpress] 输出一个过滤器绑定的方法
参考了WordPress: How do I get all the registered functions for 'the_content' filter, function print_fil ...