ASP.NET MVC + EF 利用儲存過程讀取大資料,1億資料測試很OK
阿新 • • 發佈:2018-11-28
看到本文的標題,相信你會忍不住進來看看!
沒錯,本文要講的就是這個重量級的東西,這個不僅僅支援單表查詢,更能支援連線查詢,
加入一個表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