卡桑德拉高效的桌子走

时间:2014-01-18 15:53:56

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

我目前正在制作一个基准测试(这是我的学士论文的一部分),它将基于抽象数据模型的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_name view_name col_name的每个可能组合计算字段“金额”的总和 row_name

在SQL中,这将非常简单,只需选择总和(金额)并按所需字段对其进行分组。 但是,由于Cassandra不支持这些操作(完全没问题),我需要以另一种方式实现这一点。

目前,我通过执行全表漫游,处理每个记录并将总和存储在Java的HashMap中来实现每个组合。 我使用的准备好的声明如下:

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

部分适用于有大量内存,cassandra和Java应用程序的计算机,但在较小的计算机上崩溃。

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

此外,我通过将每个分区和报告分配给单独的线程并并行运行来执行此多线程。但我想这会在应用程序方面造成很大的开销。

现在回答实际问题:你会推荐另一种执行策略来实现这个目标吗? 也许我仍然以类似SQL的方式思考太多。

感谢您的支持。

1 个答案:

答案 0 :(得分:2)

以下是两个可能对您有帮助的想法。

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'不是唯一的,这就是为什么每当再次看到相同的组合时,你维护一个hashmap来跟踪总量。这可能会更好。在cassandra中创建一个表,其中key是这四个值的组合(可能是分隔的)。如果有三个,你可以简单地为这三个使用复合键。现在,您还需要一个名为amount的列,它是一个列表。在扫描分配表(使用上述方法)时,对于每一行,执行以下操作:

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

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

很抱歉,如果我的描述令人困惑。如果有帮助,请告诉我。