【问题标题】:Where and Order By Clauses in Cassandra CQLCassandra CQL 中的 Where 和 Order By 子句
【发布时间】:2016-06-12 23:56:50
【问题描述】:

我是 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] )

【问题讨论】:

    标签: cassandra cql cql3


    【解决方案1】:

    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;
    

    首先,您需要一个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);
    

    现在,我可以按部门查询员工,他们会以empno的顺序返回给我:

    SELECT * FROM emp_by_dept WHERE dept='IT';
    

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

    对于自我推销,我深表歉意,但去年我为 DataStax 写了一篇名为 We Shall Have Order! 的文章,其中讨论了如何解决这些类型的问题。读一读,看看是否有帮助。

    编辑其他问题:

    从你的回答中我总结出关于 Cassandra 的两件事:

    (1) 没有 获取仅按具有的列排序的结果集的方法 被定义为唯一。

    (2) 当我们定义一个 PK (partition-key+clustering-key),那么结果总是有序的 通过在任何固定分区键中聚类列(我们必须限制 到一个分区键值),这意味着不需要 ORDER BY 子句,因为它永远不能改变行的顺序(在 实际存储了哪些行),即 Order By 没用。

    1) Cassandra 中的所有主键都是唯一的。无法按分区键对结果集进行排序。在我的示例中,我按empno 订购(按部门分区后)。 – 亚伦 1 小时前

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

    我在“emp”表的“empno”列上创建了一个索引,它仍然没有 允许 ORDER BY empno。那么,索引是干什么用的?他们只是为了 搜索记录以查找索引键的特定值?

    您不能按索引列对结果集进行排序。二级索引(与其对应的关系索引不同)实际上只对边缘情况、基于分析的查询有用。它们无法扩展,因此一般建议不要使用二级索引。

    好的,这只是意味着一张表不能用于获取 不同的结果集不同的条件和不同的排序 顺序。

    正确。

    因此,对于每个新需求,我们都需要创建一个新表。 IT 意味着如果我们在一个表中有十亿行(比如 Sales 表),并且 我们需要销售额总和(1)产品方面,(2)地区方面,然后我们将 将所有这些十亿行复制到 2 个表中,其中一个在集群中 Product 的顺序,另一个在 Region 的聚类顺序中。乃至 如果我们需要对每个 Salesman_id 的销售额求和,那么我们构建第三个表, 再次放置所有这些十亿行?合理吗?

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

    编辑 20160321

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

    但我发现即使这样也不正确。 Cassandra 只允许按照我们在 CREATE TABLE 的“CLUSTERING ORDER BY”中定义的方向进行排序。如果在该子句中我们定义 ASC,则它只允许按 ASC 排序,反之亦然。

    没有看到错误消息,很难知道该告诉您什么。虽然我听说过使用 ORDER BY 的查询在分区中存储的行过多时会失败。

    ORDER BY 如果您指定多个列作为排序依据,其功能也会有些奇怪。如果我定义了两个聚类列,我可以在第一列上不加选择地使用ORDER BY。但是,一旦我将第二列添加到 ORDER BY 子句,我的查询只有在我指定 both 排序方向相同(与 CLUSTERING ORDER BY 定义一样)或 both 时才有效em> 不同。如果我混合搭配,我会得到这个:

    InvalidRequest: code=2200 [Invalid query] message="Unsupported order by relation"
    

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

    【讨论】:

    • 感谢您的详细解答!我很感激。从您的回答中,我得出了关于 Cassandra 的 2 件事:(1)无法获得仅按定义为唯一的列排序的结果集,以及(2)当我们定义 PK(分区键+ clustering-key),那么结果将始终按任何固定分区键中的集群列排序(我们必须限制为一个分区键值),这意味着不需要 ORDER BY 子句,因为它永远不会改变顺序行数(实际存储行的顺序),即 Order By 没用。
    • 好的,再次感谢。还有一件事,我在“emp”表的“empno”列上创建了一个索引,它仍然不允许 ORDER BY empno。那么,索引是干什么用的?它们仅用于搜索记录以获取索引键的特定值吗?
    • 好的,这只是意味着一张表不能用于获取具有不同条件和不同排序顺序的不同结果集。因此,对于每个新需求,我们都需要创建一个新表。 IT 意味着,如果我们在一个表中有十亿行(比如 Sales 表),并且我们需要销售总和 (1) Product-wise, (2) Region-wise,那么我们将在 2 个表中复制所有这 10 亿行按Product的聚类顺序,另一个按Region的聚类顺序,。即使我们需要对每个 Salesman_id 的销售额求和,那么我们建立第三个表,再次放置所有这些十亿行?合理吗?
    • @AmirSSiddiqui 进行了编辑。评论移至回答文本。
    • 嗨 Aaron,您在上面说过“不要说 ORDER BY 没用,我会说它唯一真正的用途是在 ASC 和 DESC 之间切换排序方向。”但我发现即使这样也不正确。 Cassandra 只允许按照我们在 CREATE TABLE 的“CLUSTERING ORDER BY”中定义的方向进行排序。如果在该子句中我们定义 ASC,则它只允许按 ASC 排序,反之亦然。
    【解决方案2】:

    添加一个 redux 答案作为接受的答案很长。

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

    如果你的主键是这样定义的:

    PRIMARY KEY ((a,b),c,d)
    

    然后您将能够使用 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;
    

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

    这个查询也不行:

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

    因为 order by 目前仅支持在主键定义 c 中的 PRIMARY KEY 中声明的列的顺序在 d 之前声明,并且查询违反了将 d 放在首位的顺序。

    【讨论】:

      猜你喜欢
      • 2018-09-19
      • 2017-01-01
      • 1970-01-01
      • 2017-09-25
      • 2016-12-14
      • 1970-01-01
      • 2014-02-21
      • 2015-11-19
      • 1970-01-01
      相关资源
      最近更新 更多