大概2千多条记录吧
select top 20 * from topic
where id not in
(select top 1800 id from topic where 查询条件 order by [top] desc)
and
查询条件 order by [top] desc
然后倒数几页取出记录内容一样,就是说页数不同,但帖子列表一模一样,奇怪了。最后一页是对的。是我的语句有问题?或者请高手指点有没有其它分页语句,我试试能不能解决问题。(rs.AbsolutePage 这种写法就不用了,数据量大,这样写效率太低。)谢谢各位!

解决方案 »

  1.   

    什么是数据库分区?
    数据库分区是一种对表的横向分割,Sql server 2005企业版和之后的Sql server版本才提供这种技术,这种对表的横向分割不同于2000中的表分割,它对访问用户是透明的,用户并不会感觉的表被横向分割了。(2000中的表横向分割是建n个表例如按时间建表每月一个表,表名不同,最后需要做一个大视图)关于具体的如何做分区,请参考数据库分区演练http://www.cnblogs.com/yukaizhao/archive/2008/05/07/sql_partition_test.html 为什么要分区?
    显而易见分区是为了提高数据库的读写性能,提高数据库的效率;分区是否总是可以提高效率?
    分区是一把双刃剑,并不总能提高效率,这和具体情况有关系。
    之所以有分区技术,分区技术用的好的话可以提高性能,是因为一方面分区把一大块数据分成了n小块,这样查询的时候很快定位到某一小块上,在小块中寻址要快很多;另一方面CPU比磁盘IO快很多倍,而硬件上又有多个磁盘,或者是RAID(廉价磁盘冗余阵列),可以让数据库驱动CPU同时去读写不同的磁盘,这样才有可能可以提高效率。
    分区在有些时候并不能提高读写效率,比如说我们经常看到的按照日期字段去分区MSDN例子,这个实例中是按照记录的生成时间来分区的,把一年的数据分割成12个分区,每月一个。这样的分区导致分区并不能实现CPU同步写并提高写入性能,因为在同一个时段CPU总是要写入到最新的那一个分区对应的磁盘中。另一个问题是:这样分区是否可以提高读取性能呢?答案是不一定,要看根据什么字段来查询,如果是根据时间来查询,根据时间生成报表那么这种分区肯定会提高查询的效率,但是如果是按照某个客户查询客户最近1年内的账单数据,这样数据分布到不同的分区上,这样的话效率就不一定能提高了,这要看数据在同一个分区上连续分布的读性能高,还是CPU从几个磁盘上同步读取,然后在合并数据的性能更高一些,这和读取数据的记录数也有关系。如何分区?用什么字段做分区依据?
    具体如何分区和涉及的业务有关系,要看业务上最经常的写入和读取操作是什么,然后再考虑分区的策略。既然与具体业务相关,我们就假定一个业务环境,假如我们要做一个论坛,对论坛的帖子和回复表进行分区。
    论坛中最常见的写操作是1)发帖 2)回复帖子,
    最常见的读操作是
    1) 根据帖子id显示帖子详情和分页的帖子回复 
    2) 根据帖子版面帖子列表页根据版面id分页读取帖子列表数据
    怎么分区更合适呢?现在还没有准确答案,我有两种可能的方案,写下来,大家讨论看看。
    方案1. 根据帖子ID区域段分区(1-300w一个分区、300w-600w一个分区…),这样理论上可以提高帖子详细页的读取速度,而对于写操作性能没有益处,对于根据版面id读取帖子列表页有可能有益
    方案2. 根据版面id进行分区,这样对于写性能应该有提高,不同的分区对应不同的版面,当有两个版面同时有发帖回帖操作时,有可能可以并发写。对于根据版面id获得帖子列表页数据也可以提高性能,而对于帖子详细信息页没有性能影响。多大的数据量才需要分区?
    这个问题我只能说一个内部标准,如果一张表的记录超过在超过1000w,并以每月百万的数据量增长,那就需要分区。大家有不同的看法请回复讨论关于具体的如何做分区,请参考数据库分区演练http://www.cnblogs.com/yukaizhao/archive/2008/05/07/sql_partition_test.html[code=SQL]代码加注释,希望对初学者有用。USE [master]
    GO
    if exists (select * from sys.databases where name = 'Test_1')
    drop database Test_1
    GO
    --创建新库,要演练分区所以我们会多创建两个文件组Test_A,Test_B,以便在后面的分区方案中使用。
    CREATE DATABASE [Test_1] ON  PRIMARY 
    ( NAME = N'test_1', FILENAME = N'D:\sqldata\test_1.mdf' , SIZE = 10240KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
     FILEGROUP [test_A] 
    ( NAME = N'Test_A', FILENAME = N'D:\sqldata\test_A.ndf' , SIZE = 1024KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB ),
    FILEGROUP [test_B] 
    ( NAME = N'Test_B', FILENAME = N'D:\sqldata\test_B.ndf' , SIZE = 1024KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
     LOG ON 
    ( NAME = N'Test_log', FILENAME = N'D:\sqldata\Test_log.ldf' , SIZE = 7616KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
     COLLATE Chinese_PRC_CI_AS
    GO
    USE [Test_1]
    GO
    --若分区函数存在则先drop掉
    IF  EXISTS (SELECT * FROM sys.partition_functions WHERE name = N'test_partition')
    DROP PARTITION FUNCTION [test_partition]
    GO
    /**//*创建分区函数给后面的分区方案使用,分区函数很简单就是指定一个范围确定在某个值为什么的时候放在那个分区上*/
    --新建一个简单的分区函数,该函数以1000为界分两个区
    create partition function test_partition(int)
    AS
    RANGE LEFT FOR VALUES (1000) 
    go
    /**//*看分区方案是否存在,若存在先drop掉*/
    IF  EXISTS (SELECT * FROM sys.partition_schemes WHERE name = N'test_scheme')
    DROP PARTITION SCHEME test_scheme
    GO
    --创建分区方案,分区方案需要指定一个分区函数,并指定在分区函数中分的区需要放在哪一个文件组上
    create partition scheme test_scheme 
    AS 
    PARTITION [test_partition] TO (test_A,test_B)
    GO
    --创建分区表
    if object_id('student','U') is not null
    drop table student;
    go
    create table student
    (
        id int identity(1,1) not null,
        name varchar(10) not null,
        class int not null,
        grade int
    ) on test_scheme(class) --在此处指定该表要使用的分区方案,并将指定分区依据列
    go
    --随便插入几条数据
    insert into student values ('AQU',10,100); -- 这条数据在A分区上
    insert into student values ('AQU_边界',1000,89); -- 这边数据也在A分区上是个边界,因为我们上面在函数中指定的是RANGE LEFT,所以1000在A分区上
    insert into student values ('BQU',1001,90); -- 这一条肯定是在B分区上了。go
    --最后看看结果。$partition.分区函数(分区列)可以返回某一行所在的分区序号
    select *,分区序号 = $partition.test_partition(class) from student
    GO[/code]
      

  2.   

    其它经典的分页处理参考链接:http://blog.csdn.net/zjcxc/category/125592.aspx
      

  3.   


    --创建表开始
    if object_id('[Test]','U')is not null
    drop table [Test]
    CREATE TABLE [dbo].[Test] (
    [id] [int] IDENTITY (1, 1) NOT NULL ,
    [title] [varchar] (50) NULL 
    )
    --创建表结束
    --分页存储过程开始
    CREATE PROCEDURE dbo.sp_PagingTest
    (
    @PageSize int,
    @PageIndex int  --该过程接收两个参数,一个是当前页面一个是每页显示多少数量
    )
    AS
    begin
    declare @Count int   --声明总数
    select @Count=count(id) from Test
    select @Count 'COUNT'declare @strSQL varchar(2000)
    declare @rFrom int --声明从第几页开始
    set @rFrom = (@PageIndex - 1) * @PageSize
    if @pageIndex > 1 --如果是从第二页或者大于以上开始,那么执行下面
    begin
      set @strSQL = 'select top ' + str(@PageSize) + ' * from Test where [id] > (select max(id) from (select top ' + str(@rFrom) + ' [id] from Test order by [id] ) tempidb)'
    --上面sql得到的是当前页面所有记录
    end
    else --如果是从第一条记录 也就是第一页开始
    begin
      set @strSQL = 'select top ' + str(@PageSize) + ' * from Test order by [id]'
    --获取top n条记录填充到当前页面 ,n=pagesize
    end
    exec(@strSQL)
    --执行语句
    end
    --过程完毕
    GO
      

  4.   

    --参考:
    取n到m行1. 
    select top n-m * from tablename where id not in (select top n id from tablename order by id asc/*|desc*/) 2. 
    select top m * into 临时表(或表变量) from tablename order by columnname -- 将top m笔插入到临时表 
    set rowcount n   --只取n条结果
    select * from 表变量 order by columnname desc 3. 
    select top n * from  
    (select top m * from tablename order by columnname) a 
    order by columnname desc 
    4.如果tablename里没有其他identity列,那么: 
    先生成一个序列,存储在一临时表中.
    select identity(int) id0,* into #temp from tablename 取n到m条的语句为: 
    select * from #temp where id0 > =n and id0  <= m 如果你在执行select identity(int) id0,* into #temp from tablename这条语句的时候报错,那是因为你的DB中间的select into/bulkcopy属性没有打开要先执行: 
    exec sp_dboption 你的DB名字,'select into/bulkcopy',true 
    5.如果表里有identity属性,那么简单: 
    select * from tablename where identity_col between n and m  6.SQL2005开始.可以使用row_number() over()生成行号
    ;with cte as
    (
     select id0=row_number() over(order by id),* from tablename
    )
    select * from cte where id0 between n to m
      

  5.   

    简单的分页过程处理:
    http://blog.csdn.net/lihan6415151528/archive/2009/08/19/4461376.aspx
      

  6.   


    不行。。Invalid column name 'identity_col'.identity 是指 自动增加 id 值吗?
      

  7.   


    select * from topic where 查询条件 and id between 1800 and 1820 order by [top] desc我试了不行,查询后显示 eof
      

  8.   

    select * from topic where 查询条件 and id between 1800 and 1820 order by [top] desc
    有这样的数据没/1!
    select * from topic where 查询条件 and cast(id as int) between 1800 and 1820 order by [top] desc
      

  9.   

    避免ID重复 2000建议增加一个自增列
    2005直接用rownumber over 函数来做 
      

  10.   


    也不行,Incorrect syntax near the keyword 'from'.
      

  11.   

       我觉得用 top分页还是有缺陷! 不怎么完整,时间长了也许就会报错!