Cassandra CQL中的Where和Order By子句

Ami*_*qui 9 cql cassandra cql3

我是NoSQL数据库的新手,刚刚开始使用apache Cassandra.我在"empno"列上创建了一个带有主键的简单表"emp".这是一个简单的表,因为我们总是使用Oracle的默认scott模式.

现在我使用COPY命令和已发出的查询加载数据,Select * from emp order by empno但我很惊讶CQL不允许按empno列排序(这是PK).此外,当我使用Where条件时,它不允许在empno列上进行任何不等式操作(它表示只允许EQ或IN条件).它也没有允许任何其他列的Where和Order by,因为它们没有在PK中使用,并且没有索引.

如果我想empno在表中保持唯一并希望查询结果按排序顺序,有人可以帮助我该怎么办empno

(我的版本是:

cqlsh:demodb> show version [cqlsh 5.0.1 | Cassandra 2.2.0 | CQL spec 3.3.0 | Native protocol v4] )

Aar*_*ron 23

Cassandra的PRIMARY KEY有两个部分:

  • 分区键
  • 群集密钥

PRIMARY KEY (partitionKey1,clusteringKey1,clusteringKey2)

要么

PRIMARY KEY ((partitionKey1,partitionKey2),clusteringKey1,clusteringKey2)

分区键确定您的数据存储在哪个节点上.群集键确定分区键中数据的顺序.

在CQL中,该ORDER BY子句实际上仅用于反转聚类顺序的已定义排序方向.对于列本身,您只能CLUSTERING ORDER BY在创建表时指定子句中定义的列(并按照确切的顺序...不跳过).因此,您无法选择任意列来在查询时对结果集进行排序.

Cassandra通过使用聚类键对磁盘上的数据进行排序来实现性能,从而仅在单次读取中返回有序行(无随机读取).这就是您必须使用Cassandra采用基于查询的建模方法(通常将数据复制到多个查询表中)的原因.提前了解您的问题,并构建表格以便为其提供服务.

Select * from emp order by empno;
Run Code Online (Sandbox Code Playgroud)

首先,你需要一个WHERE条款.如果你正在使用关系数据库,没有它可以查询.使用Cassandra,您应该尽力避免未绑定的SELECT查询.此外,Cassandra只能在分区中强制执行排序顺序,因此无需查询WHERE就不会以您想要的顺序返回数据.

其次,如上所述,您需要定义群集键.如果empno要按自定义结果集,则必须找到另一列来定义分区键.尝试这样的事情:

CREATE TABLE emp_by_dept (
  empno text,
  dept text,
  name text,
  PRIMARY KEY (dept,empno)
) WITH CLUSTERING ORDER BY (empno ASC);
Run Code Online (Sandbox Code Playgroud)

现在,我可以按部门查询员工,他们将通过以下方式退回给我empno:

SELECT * FROM emp_by_dept WHERE dept='IT';
Run Code Online (Sandbox Code Playgroud)

但要明确的是,您将无法查询表中的每一行,并将其按单列排序.获得有意义的订单到结果集的唯一方法是首先以对业务案例有意义的方式对数据进行分区.运行未绑定SELECT将返回所有行(假设查询在尝试查询集群中的每个节点时没有超时),但结果集排序只能在分区内强制执行.所以你必须通过分区键来限制,以便有意义.

我为自我推销道歉,但去年我为DataStax写了一篇名为We Well Order的文章!,我在其中解决了如何解决这些类型的问题.给它一个阅读,看看它是否有帮助.

编辑其他问题:

根据你的回答,我总结了两件关于卡桑德拉的事情:

(1)无法获得仅由已定义为唯一的列排序的结果集.

(2)当我们定义PK(partition-key + clustering-key)时,结果将始终按任意固定分区键中的Clustering列(我们必须限制为一个分区键值),这意味着没有需要ORDER BY子句,因为它不能改变行的顺序(实际存储行的顺序),即Order By是无用的.

1)Cassandra中的所有PRIMARY KEY都是独一无二的.无法通过分区键订购结果集.在我的例子中,我按顺序排序empno(在由dept分区之后). - 亚伦1小时前

2)不要说ORDER BY没用,我会说它唯一真正的用途就是在ASC和DESC之间切换你的排序方向.

我在"emp"表的"empno"列上创建了一个索引,它仍然不允许ORDER BY empno.那么,索引的用途是什么?它们只用于搜索索引键的特定值的记录吗?

您无法通过索引列对结果集进行排序.二级索引(与它们的关系对应物不同)实际上仅对边缘案例,基于分析的查询有用.它们不会扩展,因此一般建议不要使用二级索引.

好吧,这只是意味着一个表不能用于获得具有不同条件和不同排序顺序的不同结果集.

正确.

因此,对于每个新需求,我们需要创建一个新表.IT意味着如果我们在一个表中有十亿行(比如Sales表),我们需要销售总和(1)产品方面,(2)区域方面,那么我们将复制2个表中的所有那些十亿行,其中一个在产品的聚类顺序中,另一个在Region的聚类顺序中.即使我们需要按Salesman_id总计销售额,那么我们构建第3个表,再次列出所有那些十亿行?这是明智的吗?

你真的要决定它是多么明智.但缺乏查询灵活性是Cassandra的缺点.为了解决这个问题,您可以继续创建查询表(IE,交易磁盘以获得性能).但如果它变得笨拙或难以管理,那么现在是时候考虑Cassandra是否真的是正确的解决方案.

编辑20160321

嗨Aaron,你在上面说过"不要说ORDER BY没用,我会说它唯一真正的用途就是在ASC和DESC之间切换排序方向."

但我发现即使这是不正确的.Cassandra只允许ORDER by与我们在CREATE TABLE的"CLUSTERING ORDER BY"caluse中定义的方向相同.如果在该子句中我们定义了ASC,它只允许ASC订购,反之亦然.

没有看到错误消息,很难知道在那个消息上告诉你什么.虽然ORDER BY在分区中存储了太多行时,我听说过查询失败.

ORDER BY如果指定多列进行排序,则函数也有点奇怪.如果我定义了两个聚类列,我可以ORDER BY不加选择地使用第一列.但是只要我将第二列添加到ORDER BY子句中,只有在指定两个排序方向相同(作为CLUSTERING ORDER BY定义)或两者都不同时,我的查询才有效.如果我混合搭配,我得到这个:

InvalidRequest: code=2200 [Invalid query] message="Unsupported order by relation"
Run Code Online (Sandbox Code Playgroud)

我认为这与数据如何存储在磁盘上有关.否则,Cassandra在准备结果集方面还有更多工作要做.然而,如果它要求所有内容匹配或镜像指定的方向CLUSTERING ORDER BY,它只能从磁盘中继顺序读取.因此,最好只在ORDER BY子句中使用单个列,以获得更可预测的结果.

  • 感谢您的详细解答!我很欣赏。根据您的回答,我得出了关于 Cassandra 的两件事:(1)无法获得仅按已定义为“唯一”的列排序的结果集,以及(2)当我们定义 PK(分区键+ clustering-key),那么结果将始终按任何固定分区键内的 Clustering 列排序(我们必须限制为一个分区键值),这意味着不需要 ORDER BY 子句,因为它永远无法更改顺序行数(行实际存储的顺序),即 Order By 是没有用的。 (2认同)

San*_*kar 7

添加一个 redux 答案作为已接受的答案相当长。

当前仅在 PRIMARY KEY 的聚集列上以及分区键受 where 子句中的 Equality 或 IN 运算符限制时支持 Order by。

也就是说,如果您的主键定义如下:

PRIMARY KEY ((a,b),c,d)
Run Code Online (Sandbox Code Playgroud)

然后,只有当您的查询具有以下条件时,您才可以使用 ORDER BY:

一个 where 子句,其中所有主键均受等式运算符 (=) 或 IN 运算符限制,例如:

SELECT * FROM emp WHERE a = 1 AND b = 'India' ORDER BY c,d;

SELECT * FROM emp WHERE a = 1 AND b = 'India' ORDER BY c;
Run Code Online (Sandbox Code Playgroud)

这两个查询是唯一有效的。

此查询也不起作用:

SELECT * FROM emp WHERE a = 1 AND b = 'India' ORDER BY d,c;
Run Code Online (Sandbox Code Playgroud)

因为 order by 当前仅支持按照主键定义中的主键中声明的顺序对列进行排序,c 已在 d 之前声明,并且查询通过将 d 首先放置而违反了顺序。