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

看到本文的標題,相信你會忍不住進來看看!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  誠邀各路高手、初學者加入。

相關文章
相關標籤/搜索