【问题标题】:Apache Cassandra stock data model designApache Cassandra 库存数据模型设计
【发布时间】:2021-03-20 22:48:27
【问题描述】:

我获得了大量有关股票价格的数据,我想为此尝试使用 Apache Cassandra。但我对主/分区/集群键不太熟悉。

我的数据库列是:

Stock_Symbol
Price
Timestamp

我的用户将始终筛选 Stock_Symbol(其中 stock_symbol=XX),然后他们可能会筛选特定时间范围(大于/小于(等于))。将有大约 30.000 个股票代码。

另外,使用另一个“过滤器”时的最大区别是什么,例如exchange_id(只有两个证券交易所可用)。

Exchange_ID
Stock_Symbol
Price
Timestamp

所以我的用户会首先过滤股票交易所(或多或少是外键),然后是股票代码(或多或少是外键)。数据也将按此顺序插入/写入。

如何选择键?

【问题讨论】:

    标签: cassandra nosql primary-key cassandra-3.0 composite-primary-key


    【解决方案1】:

    快速回答

    根据您的用例和预测的查询模式,我会为您的表推荐以下之一:

    PRIMARY KEY (Stock_Symbol, Timestamp)
    

    分区键由Stock_Symbol组成,Timestamp是唯一的聚类列。这将允许WHERE 与这两个字段一起使用。如果要过滤其中任何一个,查询中将需要过滤Stock_Symbol,并且必须作为WHERE的第一个条件。

    或者,对于您列出的第二种情况:

    PRIMARY KEY ((Exchange_ID, Stock_Symbol), Timestamp)
    

    分区键由Exchange_IDStock_Symbol组成,Timestamp是唯一的聚类列。这将允许WHERE 与这三个字段一起使用。如果要过滤这三个中的任何一个,则查询中将需要同时过滤 Exchange_IDStock_Symbol,并且必须按照该顺序作为 WHERE 的前两个条件。

    请参阅此答案的最后一部分,了解其他一些也可以根据您的需要应用的变体。

    长答案和解释

    主键、分区键和聚类列

    Cassandra 中的主键,类似于它们在关系数据库中的作用,用于识别记录并为它们编制索引,以便快速访问它们。然而,由于 Cassandra 中记录的分布式特性,它们的次要目的是确定给定记录应该存储在哪个节点上。

    Cassandra 表中的主键进一步分为两部分 - Partition Key,这是必需的,默认情况下是主键中的第一列,以及可选的 clustering column(s),它们都是在不属于分区键的主键中。

    这里有一些例子:

    PRIMARY KEY (Exchange_ID)
    

    Exchange_ID 是主键中的唯一字段,也是分区键。没有额外的聚类列。

    PRIMARY KEY (Exchange_ID, Timestamp, Stock_Symbol)
    

    Exchange_IDTimestampStock_Symbol 一起构成一个复合主键。分区键为Exchange_IDTimestampStock_Symbol 都是集群列。

    PRIMARY KEY ((Exchange_ID, Timestamp), Stock_Symbol)
    

    Exchange_IDTimestampStock_Symbol 共同构成一个复合主键。分区键由Exchange_IDTimestamp 组成。额外的括号将Exchange_IDTimestamp 分组为一个复合分区键,Stock_Symbol 是一个集群列。

    PRIMARY KEY ((Exchange_ID, Timestamp))
    

    Exchange_IDTimestamp 一起构成一个复合主键。分区键由Exchange_IDTimestamp 组成。没有聚类列。

    但他们是做什么的?

    在内部,分区键用于计算令牌,令牌确定记录存储在哪个节点上。聚类列不用于确定将记录存储在哪个节点上,但它们用于确定记录在节点内的布局顺序 - 这在查询一系列记录时很重要。聚类列值相似的记录将彼此靠近存储在同一节点上;它们“聚集”在一起。

    Cassandra 中的过滤

    由于 Cassandra 的分布式特性,字段只有在被索引时才能被过滤。这可以通过几种方式来实现,通常是作为主键的一部分或通过在字段上设置二级索引。二级索引可能会导致性能问题according to DataStax Documentation,因此通常建议尽可能使用主键来捕获您的用例。

    主键中的任何字段都可以应用WHERE 子句(与一般情况下无法过滤的未索引字段不同),但有一些规定:

    • Order Matters - WHERE 子句中的主键字段必须按照定义的顺序;如果您的主键为(field1, field2, field3),则不能使用WHERE field2 = 'value',而是必须同时包含前面的字段:WHERE field1 = 'value' AND field2 = 'value'
    • 必须存在整个分区键 - 如果将WHERE 子句应用于主键,则必须给出整个分区键,以便集群可以确定请求的数据位于集群中的哪个节点在;如果您的主键为((field1, field2), field3),则不能使用WHERE field1 = 'value',而是必须包含完整的分区键:WHERE field1 = 'value' AND field2 = 'value'

    应用于您的用例

    考虑到上述信息,您可以像您所做的那样分析用户将如何查询数据库,并将该信息用于design your data model,或者更具体地说,在这种情况下,您的主键表。

    您提到您将拥有大约 30k 个 Stock_Symbol 的唯一值,并且它始终包含在 WHERE 子句中。这听起来像是分区键的合理候选者,只要查询将只包含他们在Stock_Symbol 中搜索的单个值(例如WHERE Stock_Symbol = 'value' 而不是WHERE Stock_Symbol < 'value')。如果查询旨在返回具有多个 Stock_Symbol 中的多个值的记录,则存在集群需要从多个节点检索数据的危险,这可能会导致性能下降。

    此外,如果您的用户希望过滤 Timestamp,它也应该是主键的一部分,尽管想要过滤范围表明它可能不应该是分区键的一部分,因此它是一个很好的聚类列候选者。

    这让我想到了我的建议:

    PRIMARY KEY (Stock_Symbol, Timestamp)
    

    如果基于Stock_SymbolTimestamp 分发数据很重要,您可以引入一个基于时间但基数较小的预先计算的分时字段,例如Day_Of_WeekMonth 或类似的东西:

    PRIMARY KEY ((Stock_Symbol, Day_Of_Week), Timestamp)
    

    如果您想为过滤引入另一个字段,例如 Exchange_ID,它可以是分区键的一部分,这将要求它包含在过滤器中,或者它可以是集群列的一部分,这这意味着除非需要过滤主键中的后续字段,否则不需要它。正如您提到的,用户将始终按 Exchange_ID 过滤,然后按 Stock_Symbol 过滤,这样做可能是有意义的:

    PRIMARY KEY ((Exchange_ID, Stock_Symbol), Timestamp)
    

    或者让它成为非强制性的:

    PRIMARY KEY (Stock_Symbol, Exchange_ID, Timestamp)
    

    【讨论】:

      猜你喜欢
      • 2017-01-24
      • 2012-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-15
      相关资源
      最近更新 更多