在CQL中使用IN条件获取分区键,而不会降低性能

时间:2017-05-17 19:01:51

标签: java cassandra cql anti-patterns where-in

我已经了解了使用IN(https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlSelect.html#cqlSelect__selectInNot)的反模式。

但是如果我有一组属于同一个TokenRnage的分区键怎么办?

所以,假设我们有下一个代码:

public ResultSet getDataForFirstTokenRange(List<String> initialKeys)
    Cluster cluster = Cluster.builder().addContactPoints(DEFAULT_SEEDS)
      .withClusterName(DEFAULT_CLUSTER_NAME).build();
    Metadata meta = cluster.getMetadata();
    Set<TokenRange> tokens = meta.getTokenRanges();
    TokenRange firstTr = tokens.iterator().next();

    List<String> filteredKeys = filterKeysForToken(firstTr, initialKeys, meta)
    return session.execute(
         "select * from MY_TABLE where key IN (" + 
              String.join(
                   ", ", 
                   filteredKeys.stream()
                       .map(key -> "'" + key + "'")
                       .collect(Collectors.toList())
              )  + 
              ")"
    );
}

private List<String> filterKeysForToken(TokenRange tr, List<String> keys, Metadata meta) {
    return keys.stream()
            .filter(key -> {
                Token token = meta.newToken(TypeCodec.varchar().serialize(
                        key, 
                        ProtocolVersion.NEWEST_SUPPORTED
                ));
                return tr.contains(token);
            })
            .collect(Collectors.toList());
}

所以,这里我过滤了分区键的初始列表,因此结果列表只属于一个TokenRange。

然后我查询。

所以问题是,这里会出现性能问题吗? 如果没有,这种方法会比为每个分区密钥执行单独的查询更好吗?

1 个答案:

答案 0 :(得分:1)

我假设您已经知道分区键告诉Cassandra存储哪些节点数据。

从功能上讲,拥有多个异步查询和一个IN子句是相同的:你将击中集群中的一个节点。但是,具有IN子句应该是主要的性能损失,因为协调器在将答案返回给客户端之前等待所有数据可用。相反,如果您发出多个异步查询,则会有单独的流向客户端,每个查询一个,并且您应该能够更快地处理数据。