高效的上一页下一页分页实现思路

在进行开发的时候,最常用的功能是分页,分页的实现很简单,方法也很多,有使用存储过程实现的,也有人使用row_number函数通过sql语句直接实现分页的,这些方法开发起来简单又高效。可是随着数据量一天天增大,慢慢就可以感觉到加载越来越缓慢。罪魁祸首是由于所有分页原理都使用了select count(*)聚合函数获取总记录数,用来计算总页数。对于需要显示页码的分页形式,目前没有想到很好的实现思路。不过对于只有上一页和下一页这种的分页形式,目前发现了一个更好的实现思路,具体实现如下:

创建测试用的表,并填充数据:


CREATE TABLE sysUser
(
   id INT IDENTITY(1,1) PRIMARY KEY,
   name NVARCHAR(50),
   age INT
)

DECLARE @i INT
SET @i=0
WHILE @i<1000
BEGIN
    SET @i=@i+1
    INSERT INTO dbo.sysUser
            ( name, age )
    VALUES  ( N'User'+LTRIM(STR(@i)), -- name - nvarchar(50)
              32  -- age - int
              )
END

创建一个实体类型User:


public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }

/// <summary>
        /// 为了演示写的一个简单的调取函数
        /// </summary>
        /// <param name="sql">();
         public List<User> Query(string sql)
          {
            List<User> _list=List<User>();
            using (SqlConnection conn = new SqlConnection(数据库连接字符串))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(sql, conn))
                {
                    IDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                    while (dr.Read())
                    {
                        _list.Add(new User {  Id=dr.GetInt32(0), Name=dr.GetString(1),Age=dr.GetInt32(2)});
                    }
                    dr.Close();
                    dr.Dispose();
                }
            }
            return _list;
        }

/// <summary>
        /// 返回要显示的数据
        /// </summary>
        /// <param name="strwhere">查询条件,可为空</param>
        /// <param name="orderby">排序条件,可为空</param>
        /// <param name="page">当前页数</param>
        /// <param name="pagesize">每天显示多少条</param>
        /// <param name="hasNextPage">有些站前台最多显示多少页的数据,
///例如有些站前台最多显示100页的数据,可以传递()=>{return page<100;},要想显示所有页的数据,可以传递()=>{return true;}</param>
        /// <param name="nextpage">返回参数,大于零,列表页会显示下一页,值为零,列表页不显示下一页</param>
        /// <returns></returns>
        public List<User> GetUserList(
string strwhere, string orderby, int page, int pagesize, Func<bool> hasNextPage, out int nextpage)
        {
            string sqlorder="id desc";
            string sqlwhere=" 1=1";
            if (!string.IsNullOrEmpty(orderby)) sqlorder = orderby;
            if (!string.IsNullOrEmpty(strwhere)) sqlwhere = sqlwhere + strwhere;
            int startnum = (page - 1) * pagesize + 1;    //开始行和之前的计算方式没有变化
             //主要变化是计算结束行,结束行每次要多获取一条,目的只是为了判断下一页是否有数据,多的这一条数据并不显示在页面上
            int endnum = page * pagesize + 1;
            string sql = string.Format(
"with temp as (select id,name,age,ROW_NUMBER() over(order by {0}) as pn from sysUser where {1})
select * from temp where pn between {2} and {3}"
, sqlorder, sqlwhere, startnum, endnum);

            List<User> _list = Query(sql);
            nextpage = 0;
            if (_list.Count == pagesize + 1)
            {
                if (hasNextPage())
                {
                    nextpage = page + 1;
                }
                else
                {
                    nextpage = 0;
                }
                _list.RemoveAt(_list.Count - 1);
            }
            return _list;
        }

使用的时候只需通过如下方式进行调取:


int nextpage = 0;      //页面可以该变量来判断是否显示下一页,大于零显示下一页。
List<User> list = GetUserList("", "", page, 2, () => {return page < 48; },out nextpage);  //page为传递过来的当前第几页.

以上仅为上一页,下一页分页的一个具体实现,在数据量大的情况下,业务有没有特殊需求,只需要提供上一页下一页的情况下可以参考此类实现,减轻数据库压力。

分享到:
此条目发表在 Net 分类目录。将固定链接加入收藏夹。

评论功能已关闭。