关于索引的Cassandra IN子句

时间:2014-05-26 16:14:15

标签: cassandra cql cql3 database nosql

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

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);

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

  

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

可以使用简单的等于谓词:

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

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

(0 rows)

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

为什么这不按我预期的方式工作?我猜索引的工作方式不同。

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

1 个答案:

答案 0 :(得分:7)

虽然DataStax上的文档通常非常好,但我找不到任何讨论此背后细节的内容。但是,我确实遇到过这篇名为“Breaking Down the CQL WHERE Clause”的文章。第2节标题为“分区键中的最后一列支持IN运算符。”

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

  

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

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

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

...会支持查询,但z的值可能不是唯一的。在这种情况下,您可以将x和/或y定义为LIST<int>,然后就可以了。

此外,DataStax 确实when not to use an index上提供了文档,他们声明相同的条件适用于IN运算符的使用。

  

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