select top " + 每页行数 + " 所取字段 from 文章表 where id not in(select top " + 每页行数乘以页索引值 + " id from 文章表)我个人觉得这个SQL语句就是高效分页的核心,每次取一页数据而不是取整个表数据。
我在网上参考了一下别人做的例子总结出来的精华,就不知道我这精华臭不臭,呵呵。
看了一个高效分页存储过程例子,整个网页满满一大篇,头都看痛,我把整个例子拷贝到SQL查询分析器,一按右键执行,呵呵,好样啊,居然一点问题都没有,成功了!可是说老实话,我根本就没看懂那例子。我认为你再是天好的代码,你取数据的时候总得界定一个范围啊,还不是要进行内部计算。
我上面这个SQL语句,只要把每页行数和页索引值当作参数输入预先创建好的存储过程,不也是高效分页存储过程吗?我就是搞不懂那些例子干嘛要弄满满一大篇,是不是我这个语句执行时根本就不高效呢?
我的做法主要有两个步骤:
1、先[select count(id) from 文章表],得出总记录,从而计算页数(当然也考虑到余页问题);
2、在数据查询过程中,有个取数据时界定取值范围的内部计算,也就是后面那个SQL子句嘛。
我这样做,是不是在效率和性能上存在不足呢?
各位兄弟姐妹讨论讨论一下,谢谢!祝愿大家都进步哦。

解决方案 »

  1.   

    不会不足,我觉得挺好的!虽然sql 2005 上可以用rowcount函数,但还是比不上top原理快,有时候,简单就是最好的解决方法!
      

  2.   

     not in
     
    一看到这个就知道了
      

  3.   

    not in 
    最好換成另外的替代方式
      

  4.   

    能不能胜任,先插入百万级数据,打开SQL SERVER PROFILER,测试一下运行时间就知道
      

  5.   

    not in 啊,效率那叫一个“高”啊。你要是有个几千万条记录。你得not in个多长时间啊?不知道lz有没有对大数量数据计算过。把你的语句放到几千万条数据记录的库里面执行下就晓得效率高不高了。实践是检验真理的唯一标准嘛!
      

  6.   

    只能算数据分页中最一般的解决方案not in在大数据量时远不如in来得快最好还是存储过程解决方案
      

  7.   

    楼主,我使用你的分页和另外一个分页进行了一下测试。
    我的数据量是 109 万多点。
    另一个分页算法(假设命名为 B):
    select *
        from (select top 当前页大小 * 
                  from (select top 当前页*页大小 * from news order by id desc) a  
                  order by a.id) b
        order by b.id desc从执行计划来看,你的分页要稍优一点点,但从实际执行来看,B 要优一点。
    如果把你的也加上 order by,那么不论是执行计划还是实际执行来说,B 都要优很多。另外,如果楼主只是按 id 排序的话,根据实际情况,还会有更优的分页。
      

  8.   

    not in的分页方案能支持多字段排序.
      

  9.   

    我又测试了下后页的页,越往后面翻页,你的分页的执行计划的优势虽然越来越明显,然后实际执行效率却越来越低,我想还是耗在 not in 上。
      

  10.   

    再继续往后翻,你的分页优势却很明显了,我想,是由于分页 B 中对大量数据进行排序占用了大量资源,而 not in 此时相比之下效率还要优得多。
      

  11.   

    我测试完了
    100条万数据
    速度还行
    你的那句得该成
    select top " + 每页行数 + " 所取字段 from 文章表 where id not in(select top " + 每页行数*(以页索引值 -1)+ " id from 文章表) 
    要不第一页不显示速度平均很好贴我给你测试的代码 SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["constr"].ConnectionString);
        int ToatalCountRecord;//总记录数 
        int PageItem = 10;//每页显示的条数 
        int CurrentPage = 1;//当前页数 
        protected void Page_Load(object sender, EventArgs e)
        {
            if (!this.Page.IsPostBack)
            {
                if (Request.QueryString["page"] != null)
                {
                    if (!Int32.TryParse(Request.QueryString["page"].ToString(), out CurrentPage))
                    {
                        Response.Write("请输入分页参数!");
                        Response.End();
                        return;
                    }
                }            this.BuidGrid();
            }     }
        private void BuidGrid()
        {
            string s2 = "select top "+this.PageItem+" * from fed where serial not in (select top  "+PageItem*(CurrentPage-1)+" * from fed )";
            SqlDataAdapter da = new SqlDataAdapter(s2, conn);
            DataSet ds = new DataSet();
            //int startRecord = (CurrentPage - 1) * PageItem;
            da.Fill(ds,"a");
            this.DataList1.DataSource = ds.Tables["a"].DefaultView;
            this.DataList1.DataBind();
            SqlCommand comm = new SqlCommand("select count(*) from fed", conn);
            conn.Open();
            ToatalCountRecord = Convert.ToInt32(comm.ExecuteScalar());
            conn.Close();
            BuildPages();
        }
        private void BuildPages()
        {
            int Step = 5;//偏移量 
            int LeftNum = 0;//做界限 
            int RightNum = 0;//右界限 
            string PageUrl = Request.FilePath;
            int PageCount = (int)Math.Ceiling((double)(ToatalCountRecord) / PageItem);
            if (CurrentPage - Step < 1)
            {
                LeftNum = 1;
            }
            else
            {
                LeftNum = CurrentPage - Step;
            }
            if (CurrentPage + Step > PageCount)
            {
                RightNum = PageCount;
            }
            else
            {
                RightNum = CurrentPage + Step;
            }
            string OutPut = "";
            if (CurrentPage > 1)
            {
                OutPut += " <a href='" + PageUrl + "?page=" + (CurrentPage - 1) + "'>" + "上一页" + " </a>";
            }
            for (int i = LeftNum; i <= RightNum; i++)
            {
                if (i == CurrentPage)
                {
                    OutPut += " <font color=red>" + " " + "[" + i.ToString() + "]" + "" + " </font>";
                }
                else
                {
                    OutPut += " <a href='" + PageUrl + "?page=" + i.ToString() + "'>" + " " + "[" + i.ToString() + "]" + " " + " </a>";
                }
            }
            if (CurrentPage < PageCount)
            {
                OutPut += " <a href='" + PageUrl + "?page=" + (CurrentPage + 1) + "'>" + "下一页" + " </a>";
            }
            this.PageInfo.InnerHtml = OutPut;
        } 
      

  12.   

    -- 获取指定页的数据CREATE PROCEDURE pagination3@tblName   varchar(255),       -- 表名@strGetFields varchar(1000) = '*',  -- 需要返回的列 @fldName varchar(255)='',      -- 排序的字段名@PageSize   int = 10,          -- 页尺寸@PageIndex  int = 1,           -- 页码@doCount  bit = 0,   -- 返回记录总数, 非 0 值则返回@OrderType bit = 0,  -- 设置排序类型, 非 0 值则降序@strWhere  varchar(1500) = ''  -- 查询条件 (注意: 不要加 where)ASdeclare @strSQL   varchar(5000)       -- 主语句declare @strTmp   varchar(110)        -- 临时变量declare @strOrder varchar(400)        -- 排序类型if @doCount != 0  begin    if @strWhere !=''    set @strSQL = "select count(*) as Total from [" + @tblName + "] where "+@strWhere    else    set @strSQL = "select count(*) as Total from [" + @tblName + "]"end --以上代码的意思是如果@doCount传递过来的不是0,就执行总数统计。以下的所有代码都是@doCount为0的情况elsebeginif @OrderType != 0begin    set @strTmp = "<(select min"set @strOrder = " order by [" + @fldName +"] desc" 
     --如果@OrderType不是0,就执行降序,这句很重要!endelsebegin    set @strTmp = ">(select max"    set @strOrder = " order by [" + @fldName +"] asc"endif @PageIndex = 1begin    if @strWhere != ''      set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from [" + @tblName + "] where " + @strWhere + " " + @strOrder     else     set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["+ @tblName + "] "+ @strOrder--如果是第一页就执行以上代码,这样会加快执行速度endelsebegin--以下代码赋予了@strSQL以真正执行的SQL代码set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["    + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["+ @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["+ @fldName + "] from [" + @tblName + "]" + @strOrder + ") as tblTmp)"+ @strOrderif @strWhere != ''    set @strSQL = "select top " + str(@PageSize) +" "+@strGetFields+ "  from ["        + @tblName + "] where [" + @fldName + "]" + @strTmp + "(["        + @fldName + "]) from (select top " + str((@PageIndex-1)*@PageSize) + " ["        + @fldName + "] from [" + @tblName + "] where " + @strWhere + " "        + @strOrder + ") as tblTmp) and " + @strWhere + " " + @strOrderend end  exec (@strSQL)GO上面的这个存储过程是一个通用的存储过程,其注释已写在其中了。 
      

  13.   

    首先用not in效率不会高的,除非你按主键排序。
    最近我也再测试分页用的就是21楼的通用分页存储过程
    不过我修改了下,因为原始的程序不支持多表联合查询,也不能按时间或点击数来排序,因为这个通用的分页存储过程在按照其他字段排序时,只要那个字段有相同的值出现时,分页有问题的。
    后来没办法~自己修改,又没比较好的解决方按,我也只能用not in来了。
    我测试过100W的数据,当主键是累加一的ID时(默认聚族索引),按ID排序,分页在SQL SERVER 中执行还是很快的,我的测试数据1秒不到。但是如果按其他字段排序的话,很慢,在11秒~17秒。
    以上还只是在SQL SERVER 2005中直接执行存储过程的结果。如果在正式环境中测试的话,估计更慢。