我已经使用Docker容器在一台机器上建立了一个完全复制的3节点Cassandra集群,状态为:
Datacenter: dc_n1
=================
Status Address Load Tokens Owns Host_ID Rack
UN 172.18.0.3 83.98 MiB 256 100.0% 5bf rack_n1
Datacenter: dc_n2
=================
Status Address Load Tokens Owns Host_ID Rack
UN 172.18.0.6 83.52 MiB 256 100.0% 0518 rack_n2
Datacenter: dc_n3
=================
Status Address Load Tokens Owns Host_ID Rack
UN 172.18.0.2 83.52 MiB 256 100.0% ca95 rack_n3
现在考虑以下键空间:
create KEYSPACE stackoverflow WITH replication = {'class': 'NetworkTopologyStrategy', 'dc_n1':1,'dc_n2':1,'dc_n3':1};
和定义为的表(假设T_notID是唯一的):
create TABLE stackoverflow.TABLE (T_ID int PRIMARY KEY, T_notID int, T_Data text);
当我调度多个(例如一百个)并发Java线程向Cassandra节点提交以下两个JDBC查询时(重复一分钟),我发现(B)查询的性能下降了100倍:
(A)在表T_ID =?中选择T_Data
(B)在表T_notID =?中选择T_Data允许过滤
(B)查询还会引发许多Cassandra错误,这些错误是:com.datastax.driver.core.exceptions.ReadTimeoutException: Cassandra timeout during read query at consistency ONE (timeout while waiting for repair of inconsistent replica)
:
我了解到,通常,在查询中使用“允许过滤”是一种反模式,应格外小心,但在上面的简化示例中,由于数据已被完全复制并且每个项目的一个副本驻留在每个节点上,我不明白为什么PK查询和非PK查询的行为不同。
换句话说,考虑到在这种情况下read consistency
是ONE
的事实,并且每个节点都可以响应查询而无需与集群中的其他节点通信(无论主键定义如何),我希望从Cassandra到集中式SQL数据库都具有类似的行为。
有人可以向我解释为什么会发生这种情况和/或如何解决吗?
答案 0 :(得分:5)
当您对分区键有条件时-Cassandra知道数据在磁盘上的位置,并且可以跳转到分区开始并顺序读取数据。但是,如果您对非分区有条件,那么您的查询将需要遍历所有数据并仅过滤出必要的部分-您没有任何索引可以使Cassandra找出数据的位置。
如果您需要经常在T_notID
上运行查询,则可以创建实例化视图或二级索引(但是您需要了解它们的局限性)。
DataStax的very good blog post关于允许过滤及其使用位置。