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

06-06-05 aill
数据库是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";
    }

}
...................
<p>

上面这种算法是先获取前一页的最小值,然后获取比最小值还小的所有数据,然后获取前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++
       }
...................
<p>

上面这种算法是先获取前N页的所有数据,把前N-1也的数据排除掉

这种算法在数据量比较少的时候还可以用

但是当数据量非常大的时候,例如有100W条的时候,要获取最后一页,那么while要循环差不多100W次,这样肯定不行的!

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

    

aill
2006-06-05 16:15
可不可以这样做呢

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

banq
2006-06-06 10:39
这涉及两个方面问题:

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);

    }
<p>

aill
2006-06-06 16:34
等好几天了,一直没人回,今天老大总算出现了:)

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

但是现在必须考虑效率问题,因为要在上百万条信息里查找并翻页,而且数据库是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);

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

我们需要从另外一个角度来看待这个问题:

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

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

猜你喜欢
2Go 1 2 下一页