排序的列不是唯一值的时候如何分页获取?

数据库是SQL Server2000
当排序值是唯一值,就是按照顺序递增的时候比较好办
例如,按照datetime排序


//page:第几页,从第一页开始
//pageSize:每页多少数据
public Vector getMsgAsPage(int page, int pageSize) {
Vector rs = null;
String sql =
"";
if (page == 1) {
//当获取第一页记录的时候不能使用下面的SQL语句
sql =
"select top " + pageSize +
" * from info order by datetime DESC";
}
else {
sql =
"SELECT TOP " + pageSize +
" * FROM info WHERE (datetime <(SELECT MIN(datetime ) FROM " +
"(SELECT TOP " + (page - 1) * pageSize +
" datetime FROM info ORDER BY datetime DESC) AS TempTable)) " +
" ORDER BY datetime DESC";
}

}
...................

上面这种算法是先获取前一页的最小值,然后获取比最小值还小的所有数据,然后获取前n个,就是当前页的数据;

这种算法要求排序值必须递增/递减

但是有些信息的排序值有可能相等,例如商品的价格;要按照商品价格排序就不能利用上面的算法了;
我现在是用最笨的办法;


//page:第几页,从第一页开始
//pageSize:每页多少数据
public Vector getProduceAsPage(int page, int pageSize) {
Vector rs = null;
String sql =
"";
sql =
"select top " + pageSize*pageSize +
" * from info order by datetime DESC";

}
conn = ds.getConnection(dbsource, dburl, username, password);
stmt = conn.createStatement();
ResultSet result = stmt.executeQuery(sql);
int t=0
while (result.next()) {
if(t>=pageSize*(page-1)){
ProduceDTO p=new ProduceDTO();
p.setId(result.getString(
"id"));
....
rs.add(p);
}
t++
}
...................

上面这种算法是先获取前N页的所有数据,把前N-1也的数据排除掉
这种算法在数据量比较少的时候还可以用
但是当数据量非常大的时候,例如有100W条的时候,要获取最后一页,那么while要循环差不多100W次,这样肯定不行的!

请各位jdon的朋友指点一下,谢谢

可不可以这样做呢
在表中另外建一个列priceSort它的值==bookPrice+当前之间;这样priceSort就是唯一排序的,而且保持了bookPrice的顺序!

这涉及两个方面问题:
1. 排序算法
2.分页算法

必须将这两个方面分离,这样才能实现灵活复用的方案。

我自己是使用JdonFramework实现分页算法,然后,再使用SQL装入排序,这个排序和是否唯一值应该无关,例如代码如下:



public PageIterator getMessages(MessageQuery messageQuery, int start, int count) {
logger.debug("enter getMessage");

StringBuffer querySqlCondition = new StringBuffer(
"");
Collection paramList = new ArrayList();
//查询参数
Session session = null;
List queryList = null;

querySqlCondition.append(
" FROM message WHERE 1=1 "); //查询字符串

String categoryId = messageQuery.getCategoryId();
//发布类型
String keyword = messageQuery.getKeyword();
//关键值
String publishUser = messageQuery.getPublishUser();
//发布用户
String publishDateDomain = messageQuery.getPublishDateDomain();
//发布时间间隔
if (categoryId != null && !categoryId.equals(
"")) { //发布类型
querySqlCondition.append(
" AND categoryId = ?");
paramList.add(categoryId);
}

if (keyword != null && !keyword.equals(
"")) { //关键值
querySqlCondition.append(
" AND (subject like ? OR body LIKE ?)");
paramList.add(
"%" + keyword + "%");
paramList.add(
"%" + keyword + "%");
}

if (publishUser != null && !publishUser.equals(
"")) { //发布用户
querySqlCondition.append(
" AND Exists(SELECT userId FROM user WHERE name like ? ) ");
paramList.add(
"%"+ publishUser +"%");
}

if (publishDateDomain != null && !publishDateDomain.equals(
"")) {
//发布时间间隙
querySqlCondition.append(
" AND TO_DAYS(NOW()) - TO_DAYS(creationDate) <= ?");
paramList.add(publishDateDomain);
}

logger.debug(
"querySql = " + querySqlCondition);
logger.debug(
"parameter size = " + paramList.size());
String GET_ALL_ITEMS_ALLCOUNT =
"select count(1) " + querySqlCondition;
String GET_ALL_ITEMS =
"select messageId " + querySqlCondition;
logger.debug(
"GET_ALL_ITEMS = " + GET_ALL_ITEMS);

return pageIteratorSolver.getPageIterator(GET_ALL_ITEMS_ALLCOUNT, GET_ALL_ITEMS, paramList, start, count);

}

等好几天了,一直没人回,今天老大总算出现了:)

老大说的没错,把排序算法和分页算法分开是有利于复用,也比较灵活

但是现在必须考虑效率问题,因为要在上百万条信息里查找并翻页,而且数据库是sql server2000 里面只有top可用,不像其他数据库有startIndex等

所有sql server中公认效率比较好的就是 top 和 min/max一起使用
这样必须有一列是递增/递减的

当然我也可以用下面办法作一个通用的翻页算法,但是当页面翻到后面页面的时候效率就非常差,因为while循环要执行很多次


int startIndex;
int t=0
while(rs.next()){
if(t>=startIndex){
String a=rs.getString("a");
}
t++;
}

不知道老大这个方法中的翻页是怎么做的
return pageIteratorSolver.getPageIterator(GET_ALL_ITEMS_ALLCOUNT, GET_ALL_ITEMS, paramList, start, count);

考虑到兼容性,以及实际运行结果,也是使用你的while(rs.next())方式,Jive中也使用该方式。

我们需要从另外一个角度来看待这个问题:
while(rs.next())是低效动作,如果低效动作反复发生,而且可能是无法预知的频繁发生,这是我们最不能容忍的;如果低效动作发生频率很少,甚至只有一次,而且可以达到数据库兼容,这应该是我们设计时可以容忍的,补充,一次低效发生只影响成千上百访问请求中一次请求,就象Jsp页面第一次调用都是很慢一样(这已经成为java潜在设计文化,我发明的)。

为了达到后者设计,我们使用缓存,JF框架内部getPageIterator是这样设计。

明白bang大哥的意思了,您是利用while(rs.next)来做到通用,同时使用缓存来提高效率.我也研究研究去

>利用while(rs.next)来做到通用,同时使用缓存来提高效率
是的,是一种基于平衡策略考虑,照顾多方面。