如何增大Fetch Size以减少扫描Cassandra表时的网络调用次数
问题描述
我正在使用DataStax Java Driver 4.15版本,已阅读分页文档。
我的application.conf配置如下:
datastax-java-driver { basic.contact-points = [ "<IP>:<PORT>"] basic.request { consistency = LOCAL_QUORUM page-size = 5000 } advanced.prepared-statements { prepare-on-all-nodes = false } }
我的扫描代码如下:
ByteBuffer scan() { val query = "SELECT workflow_id, trace_id, message_key, created_at FROM workflow_message"; val stmtBuilder = new SimpleStatementBuilder(query).setPageSize(5000); if (pagingState != null) { stmtBuilder.setPagingState(pagingState); } val rs = cqlSession.execute(stmtBuilder.build()); while(rs.getAvailableWithoutFetching() > 0) { val row = rs.one(); System.out.printf("\n%s, %s, %s", row.getString("workflow_id"), row.getString("trace_id"), row.getString("message_key")) } return rs.getExecutionInfo().getPagingState(); }
我发现每次仅能读取约25行数据,请问如何增大fetch size以减少与服务器的网络调用次数?
解决方案
核心问题是混淆了page size和fetch size的作用,同时代码循环逻辑只处理了驱动本地缓存的行,没有触发后续分页拉取。
1. 明确两个参数的区别
- page size:Cassandra服务器单页返回的最大行数,你配置的5000是告诉服务器每页最多返回5000行。
- fetch size:驱动端每次从服务器拉取并缓存的行数(默认25),缓存耗尽后才会自动请求下一页。
2. 修改代码逻辑,触发完整分页获取
当前循环while(rs.getAvailableWithoutFetching() > 0)只处理了本地缓存的25行,要获取完整的一页数据,有两种方式:
方式一:直接遍历ResultSet(推荐)
遍历过程中驱动会自动在缓存耗尽时拉取下一页:
ByteBuffer scan() { String query = "SELECT workflow_id, trace_id, message_key, created_at FROM workflow_message"; SimpleStatementBuilder stmtBuilder = new SimpleStatementBuilder(query) .setPageSize(5000); if (pagingState != null) { stmtBuilder.setPagingState(pagingState); } ResultSet rs = cqlSession.execute(stmtBuilder.build()); // 遍历所有行,驱动自动处理分页拉取 for (Row row : rs) { System.out.printf("\n%s, %s, %s", row.getString("workflow_id"), row.getString("trace_id"), row.getString("message_key")); } return rs.getExecutionInfo().getPagingState(); }
方式二:一次性获取当前页所有行
用rs.all()触发驱动拉取完整的当前页数据(达到page size上限):
ByteBuffer scan() { String query = "SELECT workflow_id, trace_id, message_key, created_at FROM workflow_message"; SimpleStatementBuilder stmtBuilder = new SimpleStatementBuilder(query) .setPageSize(5000); if (pagingState != null) { stmtBuilder.setPagingState(pagingState); } ResultSet rs = cqlSession.execute(stmtBuilder.build()); // 一次性获取当前页全部行 List<Row> rows = rs.all(); for (Row row : rows) { System.out.printf("\n%s, %s, %s", row.getString("workflow_id"), row.getString("trace_id"), row.getString("message_key")); } return rs.getExecutionInfo().getPagingState(); }
3. 调整驱动fetch size(可选)
如果想减少驱动拉取次数,可以调整fetch size(不能超过page size):
- 全局配置:在
application.conf中添加:datastax-java-driver { basic.request { fetch-size = 1000 # 驱动每次拉取1000行缓存 } } - 单语句配置:在语句构建时单独设置:
SimpleStatementBuilder stmtBuilder = new SimpleStatementBuilder(query) .setPageSize(5000) .setFetchSize(1000);
内容的提问来源于stack exchange,提问作者tuk
相关产品推荐
相关产品推荐

