• 使用第三方分页AspNetPager实现真正分页的SQL原理


    AspNetPager是一个第三方分页第三方控件,可以和数据绑定控件(GridView等)方便的结合,实现真分页。

    真分页:从数据库中获取符合要求的部分数目的记录。性能较高,数据量小,网络负载小,对数据库需求小。但需要数据库端进行少量的数目筛选操作,稍占CPU。

    伪分页:GridView结合SqlDataSource自带的分页,从数据库中获取要求的全部数据,到程序中再分页。性能较低,数据量大,网络负载大,对数据库需求大。在获取大量数据时很慢。

    有关AspNetPager控件的信息,可查阅官方网站:http://www.webdiyer.com/

    下面写个简单的例子:

    1.新建数据库ILTSDB,建立一张words表,表结构如下:

    2.VS2010新建WEB窗体,并通过Entity FrameWork或linq来生成实体模型。

    3.放置GridView和AspNetPager控件.给AspNetPager控件添加个换页事件方法AspNetPager1_PageChanged,限制每页显示14条PageSize="14",其他默认。

    GridView支持自动生成列等功能,不用人工像Repeater写Eval()绑定字段代码。比较简单。所以本例使用它。

    4.编写从数据库获取所需分页数据的代码,并绑定给GridView。

    前台ASPX代码:

     1 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="AspNetPager.aspx.cs" Inherits="Test_AspNetPager" %>
     2 <%@ Register Assembly="AspNetPager" Namespace="Wuqi.Webdiyer" TagPrefix="webdiyer" %>
     3 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     4 
     5 <html xmlns="http://www.w3.org/1999/xhtml">
     6 <head runat="server">
     7     <title></title>
     8 </head>
     9 <body>
    10     <form id="form1" runat="server">
    11     <div>
    12         <asp:GridView ID="GridView1" runat="server">
    13         </asp:GridView>
    14 
    15     <webdiyer:AspNetPager ID="AspNetPager1" runat="server" PagingButtonSpacing="10px"
    16         ShowCustomInfoSection="Right" CustomInfoHTML="总记录数:%RecordCount%,总页数:%PageCount%,当前为第%CurrentPageIndex%页"
    17         Width="100%" LayoutType="Table" ShowNavigationToolTip="true" SubmitButtonText="Go"
    18         ShowPageIndexBox="Always" UrlPageIndexName="pageindex" PageSize="14" OnPageChanged="AspNetPager1_PageChanged"
    19         CssClass="paginator">
    20     </webdiyer:AspNetPager>
    21     </div>
    22     </form>
    23 </body>
    24 </html>

    后台CS代码:

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Web;
     5 using System.Web.UI;
     6 using System.Web.UI.WebControls;
     7 using Intelligent.Data.Models;
     8 
     9 public partial class Test_AspNetPager : System.Web.UI.Page
    10 {
    11     protected void Page_Load(object sender, EventArgs e)
    12     {
    13         if(!IsPostBack)
    14             ShowInfo();
    15     }
    16 
    17     protected void AspNetPager1_PageChanged(object sender, EventArgs e)
    18     {
    19         ShowInfo();
    20     }
    21 
    22     private void ShowInfo()
    23     {
    24         int recordCount = 0;
    25         int pageIndex = AspNetPager1.CurrentPageIndex;
    26         int pageSize = AspNetPager1.PageSize;
    27 
    28 
    29         ILTSDBContext dc = new ILTSDBContext();
    30         var query=dc.words.Where(w => w.wordsID < 1000);
    31         AspNetPager1.RecordCount=query.Count();
    32         GridView1.DataSource = query
    33            .OrderBy(v => v.wordsID).Skip((pageIndex - 1) * pageSize).Take(pageSize)
    34            .ToList();
    35         GridView1.DataBind();
    36         //AspNetPager1.RecordCount = recordCount;
    37     }
    38 }

    OK了,运行一把。
    效果见图:

    好,接下来我们来看下EF对数据库进行操作时,底层到底生成了什么SQL语句。

    第一反应,应该有top(),count()等函数,pageSize,beginNum(可以计算得出)等参数,最后Select出来。的确,那到底如何SQL是什么呢?!我真不确定,至少很难写,不过没事,这事EF会帮我们自动生成语句。

    打开SQL Server Management Studio,建立新SQL SERVER PROFILER,监视连接SQL SERVER的用户、操作命令、时间等等。

    我们可以根据时间、连接用户名等信息确定哪些命令是我们操作的。下面把这些命令取出,我们分析下:

     1 --repeater选取第二页数据(每页14个数据)的c#LINQ代码~实际SQL代码比较
     2 
     3 --var query = dc.words.Where(w => w.wordsID < 1000);--LINQ延迟查询,未真正查询数据库
     4 --AspNetPager1.RecordCount=query.Count();--真正查询数据库获取符合要求的总记录数,SQL语句如下
     5 SELECT [GroupBy1].[A1] AS [C1]
     6 FROM ( SELECT 
     7     COUNT(1) AS [A1]
     8     FROM [dbo].[words] AS [Extent1]
     9     WHERE [Extent1].[wordsID] < 1000
    10 )  AS [GroupBy1]
    11 --在本例中效果类似于
    12 SELECT 
    13 COUNT(1) AS [A1]
    14 FROM [dbo].[words] AS [Extent1]
    15 WHERE [Extent1].[wordsID] < 1000
    16 
    17 --获取分页数据,ToList()立即查询数据库
    18 --GridView1.DataSource = query
    19 --   .OrderBy(v => v.wordsID).Skip((pageIndex - 1) * pageSize).Take(pageSize)
    20 --   .ToList();
    21 
    22 SELECT TOP (14) 
    23 [Filter1].[wordsID] AS [wordsID], 
    24 [Filter1].[parentID] AS [parentID], 
    25 [Filter1].[wordInfo] AS [wordInfo], 
    26 [Filter1].[phonogram] AS [phonogram], 
    27 [Filter1].[sound] AS [sound], 
    28 [Filter1].[picture] AS [picture], 
    29 [Filter1].[origin] AS [origin], 
    30 [Filter1].[createUser] AS [createUser], 
    31 [Filter1].[createDate] AS [createDate], 
    32 [Filter1].[editUser] AS [editUser], 
    33 [Filter1].[editDate] AS [editDate], 
    34 [Filter1].[remark] AS [remark]
    35 FROM 
    36     (--可以单独运行下试试 
    37     SELECT [Extent1].[wordsID] AS [wordsID], [Extent1].[parentID] AS [parentID], [Extent1].[wordInfo] AS [wordInfo], [Extent1].[phonogram] AS [phonogram], [Extent1].[sound] AS [sound], [Extent1].[picture] AS 
    38     [picture], [Extent1].[origin] AS [origin], [Extent1].[createUser] AS [createUser], [Extent1].[createDate] AS [createDate], [Extent1].[editUser] AS [editUser], [Extent1].[editDate] AS [editDate], 
    39     [Extent1].[remark] AS [remark], 
    40     --函数值作为列名row_number的值
    41     row_number() OVER (ORDER BY [Extent1].[wordsID] ASC) AS [row_number]
    42         FROM [dbo].[words] AS [Extent1]
    43         WHERE [Extent1].[wordsID] < 1000
    44     )  AS [Filter1]
    45 --筛选条件就是row_number列的值,
    46 --14是一页的记录数目,>14结合之前的TOP (14)就是查询第二页信息
    47 WHERE [Filter1].[row_number] > 14
    48 ORDER BY [Filter1].[wordsID] ASC

    已经添加注释,各位理解下吧。

    这段SQL代码中,我没想到的是row_number()和新列row_number。参见http://www.cnblogs.com/icebutterfly/archive/2009/08/05/1539657.html或其他。

    好了,就写到这了。

    后记:如果不用linq或EF的话,单用ADO.NET写分页其实还真蛮复杂的,尤其是分页的SQL语句,像我这种功底不深的人是写不出来的。。。。哎。当然,写可以大牛的DBA写个存储过程在数据库里,程序员传参直接调用就好。这个方法,可以参见http://www.webdiyer.com/或者直接看实例:http://www.webdiyer.com/aspnetpagerdemo/pagedrepeater/default.aspx

  • 相关阅读:
    洛谷 P2260 [清华集训2012]模积和 || bzoj2956
    Mass Change Queries Codeforces
    Single-use Stones Codeforces
    洛谷 P4503 [CTSC2014]企鹅QQ
    洛谷 P1463 [HAOI2007]反素数
    Bear and Tower of Cubes Codeforces
    洛谷 P1593 因子和 || Sumdiv POJ
    记一次服务器inodes数报警的事件
    MySQL参数详解
    Django基础流程
  • 原文地址:https://www.cnblogs.com/nlh774/p/3477022.html
Copyright © 2020-2023  润新知