看到本文的标题,相信你会忍不住进来看看!

没错,本文要讲的就是这个重量级的东西,这个不仅仅支持单表查询,更能支持连接查询,

加入一个表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的更多相关文章

  1. ASP.NET MVC + EF 利用存储过程读取大数据

    ASP.NET MVC + EF 利用存储过程读取大数据,1亿数据测试很OK 看到本文的标题,相信你会忍不住进来看看! 没错,本文要讲的就是这个重量级的东西,这个不仅仅支持单表查询,更能支持连接查询, ...

  2. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(24)-权限组的设计和实现(附源码)(终结)

    ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框架搭建    (2):数据库访问层的设计Demo    (3):面向接口编程   (4 ):业务逻辑层的封装    ...

  3. ASP.NET MVC+EF框架+EasyUI实现权限管理系列

    http://www.cnblogs.com/hanyinglong/archive/2013/03/22/2976478.html ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开 ...

  4. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(11)-验证码实现和底层修改 ASP.NET MVC+EF框架+EasyUI实现权限管系列  (开篇)   (1):框架搭建    ...

  5. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(9)-TT模板的学习

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(9)-TT模板的学习 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框架搭建    (2): ...

  6. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(1)-框架搭建

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(1)-框架搭建 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) 前言:这篇博客开始我们便一步一步的来实现这 ...

  7. ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开篇

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列之开篇 前言:博客又有一段时间没有更新了,心里感觉这段时间空空的,好像什么都没有学下,所以就想写博客,所以就有了这个系列,这里当然也 ...

  8. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(23)-设置角色遗留问题和为权限设置角色以及EasyUI Tabs的使用

    ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框架搭建    (2):数据库访问层的设计Demo    (3):面向接口编程   (4 ):业务逻辑层的封装    ...

  9. ASP.NET MVC+EF框架+EasyUI实现权限管理系列(21)-用户角色权限基本的实现说明

    原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(21)-用户角色权限基本的实现说明     ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇)   (1):框 ...

随机推荐

  1. IP, TCP, and HTTP--reference

    IP, TCP, and HTTP Issue #10 Syncing Data, March 2014 By Daniel Eggert When an app communicates with ...

  2. 手动实现 KVO

    来源:伯乐在线 - Jerry4me 链接:http://ios.jobbole.com/88828/ 点击 → 申请加入伯乐在线专栏作者 我的Github地址 : https://github.co ...

  3. XACML-<Target> 元素的结构与相关的评估

    本文由@呆代待殆原创,转载请注明出处. 一.<Target>元素的结构 <Target>元素标识的父元素被用于评估决定请求.<Target>元素即可以做为<P ...

  4. C++重载自增/减操作符

    作为类成员使用. 前缀是先加/减1,再取值:后缀是先取值,再加/减1. 前缀是左值,返回引用:后缀是右值,返回值. 后缀多一个int参数进行区分,用时编译器会传个没用的0作实参. 在后缀实现中调用前缀 ...

  5. JD轮播图代码

    <!DOCTYPE html>   <html>   <head>   <title>jd网站的轮播图效果</title>   <me ...

  6. putty ssh login linux

    (1) in linux $ ssh-keygen -t dsa $ cd .ssh $ cat id_dsa.pub > authorized_keys $ chmod 600 authori ...

  7. Android小项目之九 两种上下文的区别

    ------- 源自梦想.永远是你IT事业的好友.只是勇敢地说出我学到! ---------- 按惯例,写在前面的:可能在学习Android的过程中,大家会和我一样,学习过大量的基础知识,很多的知识点 ...

  8. Android中Handler作用

    在Android的UI开发中,我们经常会使用Handler来控制主UI程序的界面变化.有关Handler的作用,我们总结为:与其他线程协同工作,接收其他线程的消息并通过接收到的消息更新主UI线程的内容 ...

  9. UIScrollView的相关属性说明

    _scrollView = [[UIScrollView alloc] init]; //height = 0:禁止垂直方向滚动 _scrollView.contentSize = CGSizeMak ...

  10. 基于Socket的UDP发包程序

    UDP(User Datagram Protocol,用户数据报协议)是在互联网中常用的传输层协议,该协议提供了向另一用户程序发送的消息的最简便的协议机制.与TCP一样,其默认的下层协议是IP.UDP ...