看到本文的標題,相信你會忍不住進來看看!sql
沒錯,本文要講的就是這個重量級的東西,這個不單單支持單表查詢,更能支持鏈接查詢,數據庫
加入一個表10W數據,另外一個表也是10萬數據,當你用linq創建一個鏈接查詢而後利用take,skip讀取第N頁數據的時候,測試
你的程序就掛了,由於,你極可能讀取須要幾十秒甚至幾分鐘以上。大數據
下面來說解一下,ASP.NET MVC + EF 利用存儲過程讀取大數據的詳細過程。spa
1.首先,咱們建立一個實體類PageinationInfo,主要用於分頁,以下插件
1 public class PageinationInfo 2 { 3 /// <summary> 4 /// 要顯示的表或多個表的鏈接 5 /// </summary> 6 public string strTable { get; set; } 7 8 /// <summary> 9 /// 要查詢的字段 10 /// </summary> 11 public string strField { get; set; } 12 13 /// <summary> 14 /// 每頁多少條記錄 15 /// </summary> 16 public int pageSize { get; set; } 17 18 /// <summary> 19 /// 當前頁 20 /// </summary> 21 public int pageIndex { get; set; } 22 23 /// <summary> 24 /// 查詢條件,不需where 25 /// </summary> 26 public string strWhere { get; set; } 27 28 /// <summary> 29 /// 用於排序的主鍵 30 /// </summary> 31 public string strSortKey { get; set; } 32 33 /// <summary> 34 /// 用於排序,如:id desc (多個id desc,dt asc) 35 /// </summary> 36 public string strSortField { get; set; } 37 38 /// <summary> 39 /// 排序,0-順序,1-倒序 40 /// </summary> 41 public bool strOrderBy { get; set; } 42 43 /// <summary> 44 /// 總記錄數 45 /// </summary> 46 public int RecordCount { get; set; } 47 48 /// <summary> 49 /// 總頁數 50 /// </summary> 51 public int PageCount { get; set; } 52 53 /// <summary> 54 /// 查詢耗時,毫秒爲單位 55 /// </summary> 56 public int UsedTime { get; set; } 57 58 }
2.而後咱們再DAL層新建一個類 PageinationInfoService 主要用於實現分頁讀取數據,以下:code
1 public class PageinationInfoService 2 { 3 /// <summary> 4 /// 獲取分頁列表 5 /// </summary> 6 /// <param name="pageinationInfo"></param> 7 /// <returns></returns> 8 public IList<Entity> GetPageinationInfoList<Entity>(PageinationInfo pageinationInfo) where Entity : class 9 { 10 dynamic result = null; 11 using (SnsLearningLogManagerDB db = new SnsLearningLogManagerDB()) 12 { 13 #region SqlParameter參數 14 SqlParameter[] paras = new SqlParameter[10]; 15 paras[0] = new SqlParameter("strTable", DbType.String); 16 paras[0].Value = pageinationInfo.strTable; 17 18 paras[1] = new SqlParameter("strField", DbType.String); 19 paras[1].Value = pageinationInfo.strField; 20 21 paras[2] = new SqlParameter("pageSize", DbType.Int16); 22 paras[2].Value = pageinationInfo.pageSize; 23 24 paras[3] = new SqlParameter("pageIndex", DbType.Int16); 25 paras[3].Value = pageinationInfo.pageIndex; 26 27 paras[4] = new SqlParameter("strWhere", DbType.String); 28 paras[4].Value = pageinationInfo.strWhere; 29 30 paras[5] = new SqlParameter("strSortKey", DbType.String); 31 paras[5].Value = pageinationInfo.strSortKey; 32 33 paras[6] = new SqlParameter("strSortField", DbType.String); 34 paras[6].Value = pageinationInfo.strSortField; 35 36 paras[7] = new SqlParameter("strOrderBy", DbType.Boolean); 37 paras[7].Value = pageinationInfo.strOrderBy; 38 39 paras[8] = new SqlParameter("RecordCount", DbType.Int16); 40 paras[8].Value = pageinationInfo.RecordCount; 41 paras[8].Direction = ParameterDirection.Output; 42 43 paras[9] = new SqlParameter("UsedTime", DbType.Int16); 44 paras[9].Value = pageinationInfo.UsedTime; 45 paras[9].Direction = ParameterDirection.Output; 46 #endregion 47 48 try 49 { 50 result = db.Database.SqlQuery<Entity>("exec LYBPager @strTable,@strField,@pageSize,@pageIndex,@strWhere,@strSortKey,@strSortField,@strOrderBy,@RecordCount output,@UsedTime output", paras).ToList(); 51 pageinationInfo.RecordCount = (int)paras[8].Value; 52 pageinationInfo.UsedTime = (int)paras[9].Value; 53 } 54 catch (Exception ex) 55 { 56 throw; 57 } 58 } 59 return result; 60 } 61 }
PageinationInfoService類中咱們傳入的參數是實體和PageinationInfo,實體主要是用於接收數據並封裝到實體中,LYBPager 這個是數據庫中存儲過程的名稱,而UsedTime 就是存儲過程讀取數據所用的時間
BLL層的東西,我就不貼出來了,大家或者用工廠模式或者用簡單3層,這個都可有可無。
3.接下來,咱們在Controller裏來處理咱們的業務需求,貼一段本身項目的代碼做爲分析,以下
1 public ActionResult Index(string LabelName,string _Title,string _Content, int pageNumber = 1, int pageSize = 10) 2 { 3 #region 分頁 4 SnsModels.PageinationInfo pageinationInfo = new SnsModels.PageinationInfo(); 5 pageinationInfo.pageIndex = pageNumber; 6 pageinationInfo.pageSize = pageSize; 7 pageinationInfo.RecordCount = 0; 8 pageinationInfo.strField = "*"; 9 pageinationInfo.strOrderBy = true; 10 pageinationInfo.strSortField = "ArticleID desc"; 11 pageinationInfo.strSortKey = "ArticleID"; 12 pageinationInfo.strTable = "ArticleInfo"; 13 pageinationInfo.strWhere = " 1=1"; 14 pageinationInfo.UsedTime = 0; 15 pageinationInfo.PageCount = 0; 16 #endregion 17 18 IList<SnsModels.LabelInfo> LabelInfoList = Repository.GetList<SnsModels.LabelInfo>(); 19 ViewBag.LabelInfoList = new SelectList(LabelInfoList,"LabelName","LabelName"); 20 21 #region 參數處理 22 if (LabelName != null) 23 { 24 if (!string.IsNullOrEmpty(LabelName)) 25 { 26 pageinationInfo.strWhere += " and LabelName like '%" + HttpUtility.UrlDecode(LabelName.Trim()) + "%'"; 27 ViewBag.LabelInfoList = new SelectList(LabelInfoList, "LabelName", "LabelName",LabelName.Trim()); 28 } 29 } 30 if (_Title != null) 31 { 32 if (!string.IsNullOrEmpty(_Title)) 33 { 34 pageinationInfo.strWhere += " and Title like '%" + _Title.Trim() + "%'"; 35 } 36 } 37 if (_Content != null) 38 { 39 if (!string.IsNullOrEmpty(_Content)) 40 { 41 pageinationInfo.strWhere += " and Content like '%" + _Content.Trim() + "%'"; 42 } 43 } 44 #endregion 45 46 47 IList<SnsModels.ArticleInfo> List = PageinationInfoManager.GetPageinationInfoList<SnsModels.ArticleInfo>(pageinationInfo); 48 49 #region 傳值 50 ViewBag.List = List; 51 ViewBag.pageNumber = pageNumber; 52 ViewBag.pageSize = pageSize; 53 ViewBag.RecordCount = pageinationInfo.RecordCount; 54 ViewBag.LabelName =HttpUtility.UrlDecode(LabelName); 55 ViewBag._Title = _Title; 56 ViewBag._Content = _Content; 57 #endregion 58 59 return View(); 60 }
上面咱們經過把參數傳遞到PageinationInfo,而後根據傳遞的參數拼湊pageinationInfo.strWhere現實了多條件查詢,blog
pageNumber,pageSize 咱們已經傳遞到View,你能夠經過Jquery插件展現你的分頁,點擊一下一頁的時候,跳轉回控制器就好了。排序
4,接下來,我給出存儲過程,代碼以下:ip
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(1000) = '[dbo].[ttable]',--表名 @strField varchar(1000) = '*', --查詢字段 @pageSize int = 10, --每頁多少條記錄 @pageIndex int = 1, --當前頁 @strWhere varchar(1000) = '1=1', --查詢條件 @strSortKey varchar(1000) = 'id', --主鍵 @strSortField varchar(500) = 'id DESC', --排序 @strOrderBy bit = 1, --是否排序 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(500),@where1 varchar(200),@where2 varchar(200) 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=1 --第一頁 BEGIN SET @sql='SELECT TOP '+CAST(@pageSize AS varchar(200))+' '+@strField+' FROM '+@strTable+@where2+'ORDER BY '+ @strSortField END Else BEGIN IF @strOrderBy=0 SET @sql='SELECT TOP '+CAST(@pageSize AS varchar(200))+' '+@strField+ ' FROM '+ @strTable+@where1+@strSortKey+'>(SELECT MAX('+case when charindex('.',@strSortKey)>0 then right(@strSortKey,len(@strSortKey)-charindex('.',@strSortKey)) else @strSortKey end+') '+ ' FROM (SELECT TOP '+ CAST(@pageSize*(@pageIndex-1) AS varchar(200))+' '+@strSortKey+' FROM '+@strTable+@where2+ 'ORDER BY '+@strSortField+') t) ORDER BY '+@strSortField ELSE SET @sql='SELECT TOP '+CAST(@pageSize AS varchar(200))+' '+@strField+' FROM '+@strTable+@where1+ @strSortKey+'<(SELECT MIN('+case when charindex('.',@strSortKey)>0 then right(@strSortKey,len(@strSortKey)-charindex('.',@strSortKey)) else @strSortKey end+') '+ ' FROM (SELECT TOP '+CAST(@pageSize*(@pageIndex-1) AS varchar(200))+' '+ @strSortKey+' FROM '+@strTable+@where2+'ORDER BY '+@strSortField+') t) ORDER BY '+@strSortField+'' END print @sql --select @RecordCount EXEC(@sql) print @sql If @@Error <> 0 Begin RollBack Tran Return -1 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 誠邀各路高手、初學者加入。