1. 程式人生 > >ASP.NET MVC + EF 利用儲存過程讀取大資料,1億資料測試很OK

ASP.NET MVC + EF 利用儲存過程讀取大資料,1億資料測試很OK

 看到本文的標題,相信你會忍不住進來看看!   沒錯,本文要講的就是這個重量級的東西,這個不僅僅支援單表查詢,更能支援連線查詢,   加入一個表10W資料,另一個表也是10萬資料,當你用linq建立一個連線查詢然後利用take,skip讀取第N頁資料的時候,   你的程式就掛了,因為,你很可能讀取需要幾十秒甚至幾分鐘以上。   下面來講解一下,ASP.NET MVC + EF 利用儲存過程讀取大資料的詳細過程。   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 主要用於實現分頁讀取資料,如下:   複製程式碼  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現實了多條件查詢,   pageNumber,pageSize 我們已經傳遞到View,你可以通過Jquery外掛展示你的分頁,點選一下一頁的時候,跳轉回控制器就行了。       4,接下來,我給出儲存過程,程式碼如下:   複製程式碼 USE [LearningLogManager
DB2
] 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 ('
[email protected]
+') AND ' --本來有條件再加上此條件             SET @where2=' WHERE ('[email protected]+') ' --原本沒有條件而加上此條件         END     --SET @sql='SELECT @intResult=COUNT(*) FROM '[email protected][email protected]
      BEGIN         SET @sql='SELECT @sqlcount=COUNT(*) FROM (select '[email protected]+' 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))+' '[email protected]+' FROM '[email protected][email protected]+'ORDER BY '+ @strSortField         END     Else         BEGIN             IF @strOrderBy=0                 SET @sql='SELECT TOP '+CAST(@pageSize AS varchar(200))+' '[email protected]+ ' FROM '+                     @[email protected][email protected]+'>(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))+' '[email protected]+' FROM '[email protected][email protected]+                     'ORDER BY '[email protected]+') t) ORDER BY '[email protected]             ELSE                 SET @sql='SELECT TOP '+CAST(@pageSize AS varchar(200))+' '[email protected]+' FROM '[email protected][email protected]+                     @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 '[email protected][email protected]+'ORDER BY '[email protected]+') t) ORDER BY '[email protected]+''         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群,並且都很踴躍提問 http://www.2cto.com/kf/201407/321690.html