【问题标题】:Cassandra efficient table walkCassandra 高效的餐桌步行
【发布时间】:2014-01-18 15:53:56
【问题描述】:

我目前正在研究基于抽象数据模型和抽象查询来比较 SQL 和 NoSQL 数据库的基准测试(这是我的学士论文的一部分),以实现在所有系统上的公平实施。

我目前正在执行指定如下的查询: 我在 Cassandra 中有一个表,指定如下:

CREATE TABLE allocated(
    partition_key int, 
    financial_institution varchar, 
    primary_uuid uuid,
    report_name varchar,
    view_name varchar,
    row_name varchar,
    col_name varchar,
    amount float,
PRIMARY KEY (partition_key, report_name, primary_uuid));

此表包含大约 100,000,000 条记录 (~300GB)。

我们现在需要为 report_nameview_namecol_name 的每个可能组合计算字段“amount”的总和row_name

在 SQL 中这很容易,只需选择 sum(金额)并按您想要的字段对其进行分组。 但是,由于 Cassandra 不支持这些操作(这很好),我需要以另一种方式实现这一点。

目前,我通过执行全表遍历、处理每条记录并将每个组合的总和存储在 Java 中的 HashMap 中来实现这一点。 我使用的prepared statement如下:

SELECT 
   partition_key, 
   financial_institution,
   report_name, 
   view_name, 
   col_name, 
   row_name, 
   amount 
FROM allocated; 

这部分适用于 cassandra 和 Java 应用程序都具有大量 RAM 的机器,但在较小的机器上会崩溃。

现在我想知道是否有可能以更快的方式实现这一目标? 我可以想象使用 partition_key,它也用作 cassandra 分区键并对每个分区执行此操作(我有 5 个)。

我还考虑通过分配每个分区并报告给单独的线程并并行运行来执行此多线程。但我想这会在应用程序端造成大量开销。

现在回到实际问题:您会推荐另一种执行策略来实现这一目标吗? 可能我还是用类似 SQL 的方式想的太多。

感谢您的支持。

【问题讨论】:

    标签: nosql cassandra sum aggregate-functions full-table-scan


    【解决方案1】:

    这里有两个想法可能对您有所帮助。

    1) 您可以使用以下方法有效地扫描任何表中的行。考虑一个带有 PRIMARY KEY (pk, sk, tk) 的表。让我们使用 1000 的提取大小,但您可以尝试其他值。

    第一个查询(Q1):

    select whatever_columns from allocated limit 1000;
    

    处理这些,然后记录构成主键的三列的值。假设这些值为 pk_val、sk_val 和 tk_val。这是您的下一个问题(Q2):

    select whatever_columns from allocated where token(pk) = token(pk_val) and sk = sk_val and tk > tk_val limit 1000;
    

    上述查询将查找相同 pk 和 sk 的记录,但查找 tk 的下一个值。只要您不断获得 1000 条记录,就不断重复。当得到更少的东西时,你会忽略 tk,而在 sk 上做得更大。这是查询(Q3):

    select whatever_columns from allocated where token(pk) = token(pk_val) and sk > sk_val limit 1000;
    

    同样,只要您获得 1000 行,就继续这样做。完成后,运行以下查询(Q4):

    select whatever_columns from allocated where token(pk) > token(pk_val) limit 1000;
    

    现在,您再次使用最后一条记录中的 pk_val、sk_val、tk_val,并使用这些值运行 Q2,然后是 Q3,然后是 Q4.....

    当 Q4 返回小于 1000 时,您就完成了。

    2) 我假设'report_name、view_name、col_name 和 row_name' 不是唯一的,这就是为什么您维护一个哈希图以在您再次看到相同的组合时跟踪总金额。这是一些可能会更好的方法。在 cassandra 中创建一个表,其中键是这四个值的组合(可能是分隔的)。如果有三个,您可以简单地为这三个使用复合键。现在,您还需要一个名为数量的列,它是一个列表。当您扫描分配表时(使用上述方法),对于每一行,您执行以下操作:

    update amounts_table set amounts = amounts + whatever_amount where my_primary_key = four_col_values_delimited;
    

    完成后,您可以扫描此表并计算您看到的每一行的列表总和,并将其转储到您想要的任何位置。请注意,由于只有一个键,因此您只能使用 token(primary_key) > token(last_value_of_primary_key) 进行扫描。

    对不起,如果我的描述令人困惑。如果这有帮助,请告诉我。

    【讨论】:

    • 至 #2) 我可能会以这种方式重新实现它。这对我来说听起来比我的 HashMap 实现要好得多,它最终导致我昨天为我的 JVM 使用了大约 2GB 的 RAM。 To #1):我得到了大部分的概念。我不确定 Query3 和 Query4。假设 pk,sk,tk 在层次结构中排序,当在第二季度获得少于 1000 个结果时,我是否不必立即跳到下一个 sk,因为相同 (pk, sk) 和随机 tk 的所有组合筋疲力尽? ....或者我不明白这一点再次感谢您的帮助:)
    • "假设 pk,sk,tk 在层次结构中排序,当 Q2 得到少于 1000 个结果时,我是否必须立即跳转到下一个 sk" 当 Q2 返回小于 1000 ,你知道当前的pk_val、sk_val组合没有更多的值了(所有tk_val都被扫描过了)。因此,您需要寻找相同 pk_val 的下一个 sk 值,这可以使用 Q3 完成。 (很抱歉进行了编辑,但我没有意识到按回车键会发表评论。此外,格式似乎在 cmets 中不起作用。)。
    猜你喜欢
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 1970-01-01
    • 2013-07-16
    • 1970-01-01
    • 2010-12-10
    相关资源
    最近更新 更多