• 100w条记录分页,可以有多快?—— DataReader分页与SQL语句分页的对比测试(在线演示)


      上周看到了两篇关于DataReader分页的帖子,帖子的观点都是可以是用DataReader来分页,而且效率还不错。

      根据我的分页经历来看,很难理解DataReader分页怎么就快了呢?理论上就不说了,直接用测试说话。

      1、100w条记录,使用SQL语句(max方法)分页,PostBack方式,GridView显示数据。(第一页需要统计总记录数,所以会有点慢)http://demo.naturefw.com/Nonline/QuickPager/200w/GridView.aspx

      2、100w条记录,使用DataReader分页,URL方式,GridView显示数据(没有统计总记录数。没做分页UI,需要直接修改参数查看其他页)。http://demo.naturefw.com/Nonline/QuickPager/200w/GridViewReader.aspx?page=1

      运行环境

      SQL Server 2000 。数据库里只有一个表(八个字段),总记录数1181856。数据库文件体积438MB。

      windows Server 2000、asp.net2.0

      测试结果

      1、SQL语句(max方法),前若干页(不包括第一页),只需要十几毫秒。最后若干页,需要300多毫秒,不超过0.5s。

      2、DataReader分页。很平稳,不管是前面的还是后面的,都是1.5s左右。

      有在线测试(见上面的连接),大家可以自己看看。

      测试说明:

      1、使用的是QuickPager分页控件,由QuickPagerSQL(单独的类库)动态拼接SQL,所以在测试页面下面会出现"拼接SQL用时",这个也是顺便看看拼接SQL的效率。

      另外请注意一下,在显示第一页的时候,会使用count(0)来统计一下总记录数,所以显示第一页的时候,时间会长一点。

      由于是动态拼接的SQL语句,没有使用存储过程,所以每次分页,都可以查看到使用的SQL。

    开始时间:2011-05-05 12:02:59
    拼接SQL用时:0秒0毫秒
    加载数据用时:0秒0毫秒
    绑定控件用时:0秒0毫秒
    提取数据使用的SQL语句:
    select top 10 * from Person_User_ViewLog where logid <= (SELECT min(logid ) from (select top 61 logid from Person_User_ViewLog order by logid desc ) as t ) order by logid desc

      2、DataReader分页。由于QuickPager分页控件不支持DataReader分页,所以临时写的代码。没有做分页的UI(偷懒了,大家包涵),采用URL的分页方式,page 表示页号。

      测试分析

      在这个测试里,DataReader分页慢的原因是数据比较大——100w。如果数据比较少,只有几百条的话,那么差距不会这么大。

      通过测试结果来看,DataReader分页,在速度上完全没有优势。只是在更换数据库上有点优势。不过 QuickPagerSQL 可以产生不同的分页算法来应对不同类型的数据库,DataReader的优势也就不明显了。

      测试代码

      1、SQL分页

    public partial class GridView : Page
    {
    protected DateTime dtStartTime;    //页面开始时间
    protected DateTime dtSQLTime;      //拼接SQL结束时间
    protected DateTime dtLoadDataTime; //加载数据结束时间
    protected DateTime dtBindDataTime; //绑定控件结束时间
    #region 初始化
    protected override void OnInit(EventArgs e)
    {
    base.OnInit(e);
    string cnString = ConfigurationManager.AppSettings["cnStringTest"];
    DataAccessLibrary dal = DALFactory.CreateDAL(cnString, "System.Data.SqlClient");
    //数据访问函数库的实例,使用基类里定义的。
    Pager1.DAL = dal;
    //设置显示数据的控件
    Pager1.ShowDataControl = GV;
    //定义QuickPager_SQL,设置Page属性
    Pager1.PagerSQL.Page = this;
    //默认是PostBack的分页方式
    dtStartTime = DateTime.Now;
    }
    #endregion
    protected void Page_Load(object sender, EventArgs e)
    {
    lblMsg.Text = "开始时间:" + dtStartTime.ToString("yyyy-MM-dd HH:mm:ss 
    "); if (!Page.IsPostBack) { SetPagerInfo(); //设置表名、字段名等 } } #region 给QuickPager_SQL 设置属性,以便拼接SQL private void SetPagerInfo() { //表名或者视图名,必须设置 Pager1.PagerSQL.TableName = " Person_User_ViewLog"; //表名或者视图名称 //一些分页算法必须设置主键。 Pager1.PagerSQL.TablePKColumn = "LogID"; //主键名称,不支持复合主键 //排序字段也是必须设置的,否则就无法准确分页 Pager1.PagerSQL.TableOrderByColumns = "LogID desc "; //排序字段,根据分页算法而定,可以支持多个排序字段 //默认TableShowColumns是 * ,可以不设置 //Pager1.PagerSQL.TableShowColumns = "*"; //需要显示的字段 //没有查询条件,那就不用设置了嘛。 //Pager1.PagerSQL.TableQuery = ""; //查询条件 //默认一页20条记录 Pager1.PageSize = 10; //一页显示的记录数 //设置分页方式,默认是Max_TopTop Pager1.PagerSQL.SetPagerSQLKind = PagerSQLKind.Max_TopTop ; } #endregion #region 在拼接SQL和提取数据、自动绑定控件之前触发, protected void Pager1_PageChanged(object sender, PageArgs e) { //在拼接SQL和提取数据、自动绑定控件之前触发, dtSQLTime = DateTime.Now; TimeSpan ts = dtSQLTime - dtStartTime; lblMsg.Text += string.Format("拼接SQL用时:{0}秒{1}毫秒
    ", ts.Seconds, ts.Milliseconds); } #endregion #region 加载数据时间 protected void Pager1_PreGridBind(object sender, PageArgs e) { //在提取数据之后,自动绑定控件之前触发 //计算时间 dtLoadDataTime = DateTime.Now; TimeSpan ts = dtLoadDataTime - dtSQLTime; lblMsg.Text += string.Format("加载数据用时:{0}秒{1}毫秒
    ", ts.Seconds, ts.Milliseconds); } #endregion #region 绑定控件时间 protected void Pager1_GridBinded(object sender, PageArgs e) { //在自动绑定控件之后触发 //计算时间 dtBindDataTime = DateTime.Now; TimeSpan ts = dtBindDataTime - dtLoadDataTime; lblMsg.Text += string.Format("绑定控件用时:{0}秒{1}毫秒
    ", ts.Seconds, ts.Milliseconds); lblMsg.Text += "提取数据使用的SQL语句:
    "; lblMsg.Text += Pager1.PagerSQL.GetSQLByPageIndex(Pager1.PageIndex); //测试用 } #endregion }

    2、DataReader分页(如果代码有什么问题,还请大家多多指正!)

    public partial class GridView : Page
    public partial class GridViewReader : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                bind();
            }
    
            //绑定控件
            private void bind()
            {
                string pageIndex = Request.QueryString["page"];
    
                if (!Functions.IsInt(pageIndex ))
                {
                    Functions.PageRegisterAlert(Page,"参数不正确!");
                    return;
                }
    
                int pIndex = int.Parse(pageIndex);
    
                if (pIndex < 0)
                {
                    Functions.PageRegisterAlert(Page, "页号不能小于0 !");
                    return;
                }
    
                DateTime dt1 = DateTime.Now;
    
                GV.DataSource = LoadData(pIndex);
    
                DateTime dt2 = DateTime.Now;
    
                TimeSpan ts = dt2 - dt1;
                lblMsg.Text = string.Format("用时{0}秒{1}毫秒", ts.Seconds, ts.Milliseconds);
     
                GV.DataBind();
            }
    
            private DataTable LoadData(int pageIndex)
            {
                int pageSize = 10;
    
                string cnString =  ConfigurationManager.AppSettings["cnStringTest"];
    
                string sql = "select * from Person_User_ViewLog order by LogID desc ";
    
                SqlConnection cn = new SqlConnection(cnString);
                SqlCommand cm = new SqlCommand(sql,cn);
    
                cn.Open();
                using (SqlDataReader reader = cm.ExecuteReader())
                {
                    DataTable dt = new DataTable();
                    int fieldCount = reader.FieldCount;
                    for (int i = 0; i < fieldCount; i++)
                    {
                        DataColumn col = new DataColumn();
                        col.ColumnName = reader.GetName(i);
                        col.DataType = reader.GetFieldType(i);
                        dt.Columns.Add(col);
                    }
                    int totalCount = 0;
                    int first = (pageIndex - 1) * pageSize + 1;
                    int last = pageIndex * pageSize;
                    while (reader.Read())
                    {
                        totalCount++;
                        //退出reader
                        if (totalCount > last)
                            break;
                    
                        if (totalCount >= first && totalCount <= last )
                        {
                            //取值
                            DataRow r = dt.NewRow();
                            for (int i = 0; i < fieldCount; i++)
                            {
                                r[i] = reader[i];
                            }
                            dt.Rows.Add(r);
    
    
                        }
                    }
                    return dt;
                }
    
            }
        }
    

      QuickPager分页控件的在线演示

      QuickPager分页控件的在线帮助文档

      QuickPager分页控件源码下载 V2.0.4.5

  • 相关阅读:
    sql字符串函数(转)
    sqlserver 导入/导出Excel
    SelectSingleNode和SelectNodes区别
    iOS sqlite 的各种操作
    iOS 自定义的对象类型的解档和归档
    开放-封闭原则(OCP)开-闭原则 和 依赖倒转原则,单一职责原则
    iOS UITableView , UITableViewController ,UITableViewCell实现全国各省市遍历,选择相应的地区
    iOS 页面跳转传值,属性传值,代理传值,代码块传值,单例传值,通知传值
    iOS中的事件传递和响应者链条
    iOS开发 首次启动显示用户引导,第二次启动直接进入App,UIScrollView,UIPageControl,NSUserDefaults
  • 原文地址:https://www.cnblogs.com/jyk/p/2037538.html
Copyright © 2020-2023  润新知