关于索引的Cassandra IN子句

Kor*_*nel 6 database cql cassandra nosql cql3

假设一个简单的表有一个插入(或没有这个插入,并不重要).

CREATE TABLE test (
 x int,
 y int,
 z int,
 PRIMARY KEY (x, y, z)
);


create index z_index on test (z);

insert into test(x, y, z) values (1,2,3);
Run Code Online (Sandbox Code Playgroud)

我很难理解为什么我不能在索引z上使用in子句进行查询:

cqlsh:test> select*from test其中z in(3);
错误请求:PRIMARY KEY部分z不能被限制(前面部分y不受限制或非EQ关系)

可以使用简单的equals谓词:

cqlsh:test> select * from test where z = 3;

 x | y | z
---+---+---
 1 | 2 | 3

(0 rows)
Run Code Online (Sandbox Code Playgroud)

我认为在z上有一个索引会保留从z的特定值到行的映射,但这个假设似乎是错误的.

为什么这不符合我的预期?我猜索引的工作方式不同.

编辑:我正在使用[cqlsh 4.1.1 | Cassandra 2.0.6 | CQL规范3.1.1 | 节俭协议19.39.0]

Aar*_*ron 7

虽然关于DataStax的文档通常非常好,但我找不到任何讨论这背后细节的内容.但是,我确实遇到过这篇名为" 打破CQL WHERE子句 "的文章.第2节的标题是" 分区键中的最后一列支持IN运算符".

换句话说,它基本上是这样说的:

对于单列分区键,允许IN运算符不受限制.对于复合分区键,我必须在分区键的前N-1列上使用=运算符,以便在最后一列上使用IN运算符.

在您的情况下,x是您的分区键,这意味着它x是唯一支持INCQL运算符的列.如果您确实需要能够支持IN列上的查询z,那么您必须对数据进行反规范化,并构建一个旨在支持该查询的(冗余)表.例如:

CREATE TABLE test (
 x int,
 y int,
 z int,
 PRIMARY KEY (z)
);
Run Code Online (Sandbox Code Playgroud)

...将支持查询,但值z可能不是唯一的.在这种情况下,您可以定义x和/或y作为a LIST<int>和那样做.

此外,DataStax 确实提供了何时不使用索引的文档,并指出相同的条件适用于IN运算符的使用.

在大多数情况下,不建议在WHERE子句中使用IN.使用IN会降低性能,因为通常必须查询许多节点.例如,在具有30个节点,复制因子为3且一致性级别为LOCAL_QUORUM的单个本地数据中心集群中,单个密钥查询将发送到两个节点,但如果查询使用IN条件,则数量为被查询的节点很可能甚至更高,最多20个节点,具体取决于密钥落在令牌范围内的位置.