ClickHouseStatement statement = null;
try {
statement = connection.createStatement();
ClickHouseRowBinaryInputStream in = statement.executeQueryClickhouseRowBinaryStream(sql);
ClickHouseBitmap bit = in.readBitmap(ClickHouseDataType.UInt64);
Roaring64NavigableMap obj = (Roaring64NavigableMap) bit.unwrap();
return new ExtRoaringBitmap(obj);
} catch (Exception e) {
log.error("查询位图错误 [ip:{}][sql:{}]", ip, sql, e);
throw e;
} finally {
DbUtils.close(statement);
}
上面的方法直接读取Bitmap会大量占用应用内存,怎么进行优化呢?
我们可以通过Clickhouse把Bitmap转成列,通过流式读取bitmap里的offset,在应用里创建Bitmap
private static String SQL_WRAP = "SELECT bitmap_arr AS offset FROM (SELECT bitmapToArray(aplus_bitmap) AS bitmap_arr FROM (SELECT ({}) AS aplus_bitmap LIMIT 1)) ARRAY JOIN bitmap_arr";
public static Roaring64NavigableMap getBitmap(Connection conn, String sql){
Statement statement = null;
ResultSet rs = null;
try {
statement = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
String exeSql = ATool.format(SQL_WRAP, sql);
rs = statement.executeQuery(exeSql);
Roaring64NavigableMap bitmap = new Roaring64NavigableMap();
while (rs.next()) {
Long offset = rs.getLong(1);
if(offset != null){
bitmap.add(offset);
}
}
return bitmap;
} catch (Exception e){
log.error("从CK读取bitmap错误, SQL:{}", sql, e);
} finally {
ATool.close(rs, statement);
}
return null;
}
这里我们在创建Statement时设置了ResultSet.TYPE_FORWARD_ONLY这个参数,在从ResultSet(结果集)中读取记录的时,对于访问过的记录就自动释放了内存。
进一步减少了内存的使用。