开发者社区> 问答> 正文

如何实现分页查询



限制条件


不同于传统关系型数据库支持的翻页查询,在NoSQL的数据模型和API上,实现分页功能有以下限制:

  • 不支持获取整个范围的行数,即无法计算总的页数。
  • 不建议使用设置offset来跳页,因为offset的过滤是在客户端进行,服务端扫描读出的数据是固定的。若offset设定过大,则可能导致本次查询时间过长。
  • 仅提供顺序翻页的功能,一页一页顺序往下翻。


示例代码


下面是一个实现分页读接口的示例代码,提供offset过滤以及读取指定页数的数据: /**
     * 范围查询指定范围内的数据,返回指定页数大小的数据,并能根据offset跳过部分行。
     */
    private static Pair<List<Row>, RowPrimaryKey> readByPage(OTSClient client, String tableName,
            RowPrimaryKey startKey, RowPrimaryKey endKey, int offset, int pageSize) {
        Preconditions.checkArgument(offset >= 0, "Offset should not be negative.");
        Preconditions.checkArgument(pageSize > 0, "Page size should be greater than 0.");
        List<Row> rows = new ArrayList<Row>(pageSize);
        int limit = pageSize;
        int skip = offset;
        RowPrimaryKey nextStart = startKey;
        // 若查询的数据量很大,则一次请求有可能不会返回所有的数据,需要流式查询所有需要的数据。
        while (limit > 0 && nextStart != null) {
            // 构造GetRange的查询参数。
            // 注意:startPrimaryKey需要设置为上一次读到的位点,从上一次未读完的地方继续往下读,实现流式的范围查询。
            RangeRowQueryCriteria criteria = new RangeRowQueryCriteria(tableName);
            criteria.setInclusiveStartPrimaryKey(nextStart);
            criteria.setExclusiveEndPrimaryKey(endKey);
            // 需要设置正确的limit,这里期望读出的数据行数最多为完整的一页数据以及需要过滤(offset)的数据
            criteria.setLimit(skip + limit);
            GetRangeRequest request = new GetRangeRequest();
            request.setRangeRowQueryCriteria(criteria);
            GetRangeResult response = client.getRange(request);
            for (Row row : response.getRows()) {
                if (skip > 0) {
                    skip--; // 对于offset之前的数据,需要过滤掉,采用的策略是读出来后在客户端进行过滤。
                } else {
                    rows.add(row);
                    limit--;
                }
            }
            // 设置下一次查询的起始位点
            nextStart = response.getNextStartPrimaryKey();
        }
        return new Pair<List<Row>, RowPrimaryKey>(rows, nextStart);
    }


下面是使用以上接口,顺序地一页一页读取某个指定范围内的所有数据的例子: private static void readByPage(OTSClient client, String tableName) {
        int pageSize = 8;
        int offset = 33;
        RowPrimaryKey startKey = new RowPrimaryKey();
        startKey.addPrimaryKeyColumn(COLUMN_GID_NAME, PrimaryKeyValue.INF_MIN);
        startKey.addPrimaryKeyColumn(COLUMN_UID_NAME, PrimaryKeyValue.INF_MIN);
        RowPrimaryKey endKey = new RowPrimaryKey();
        endKey.addPrimaryKeyColumn(COLUMN_GID_NAME, PrimaryKeyValue.INF_MAX);
        endKey.addPrimaryKeyColumn(COLUMN_UID_NAME, PrimaryKeyValue.INF_MAX);
        // 读第一页,从范围的offset=33的行开始读起
        Pair<List<Row>, RowPrimaryKey> result = readByPage(client, tableName, startKey, endKey, offset, pageSize);
        for (Row row : result.getKey()) {
            System.out.println(row.getColumns());
        }
        System.out.println("Total rows count: " + result.getKey().size());
        // 顺序翻页,读完范围内的所有数据
        startKey = result.getValue();
        while (startKey != null) {
            System.out.println("============= start read next page ==============");
            result = readByPage(client, tableName, startKey, endKey, 0, pageSize);
            for (Row row : result.getKey()) {
                System.out.println(row.getColumns());
            }
            startKey = result.getValue();
            System.out.println("Total rows count: " + result.getKey().size());
        }
    }

展开
收起
云栖大讲堂 2017-10-26 10:35:34 3557 0
1 条回答
写回答
取消 提交回答
  • Re如何实现分页查询
    没看懂
    2017-12-12 15:28:54
    赞同 展开评论 打赏
问答排行榜
最热
最新

相关电子书

更多
MySQL查询优化实战 立即下载
低代码开发师(初级)实战教程 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载