4

我将 Cassandra 1.2.7 与使用 CQL3 的官方 Java 驱动程序一起使用。

假设一个表由

CREATE TABLE foo ( 
    row int, 
    column int, 
    txt text, 
    PRIMARY KEY (row, column)
);

然后我想执行相当于SELECT DISTINCT row FROM foo

据我了解,应该可以在 Cassandra 的数据模型中有效地执行此查询(鉴于复合主键的实现方式),因为它只会查询“原始”表。

我搜索了 CQL 文档,但没有找到任何选项。

我的备份计划是创建一个单独的表 - 比如

CREATE TABLE foo_rows (
    row int,
    PRIMARY KEY (row)
);

但这需要保持两者同步的麻烦 - 写入 foo_rows 以获取 foo 中的任何写入(也是性能损失)。

那么有没有办法查询不同的行(分区)键?

4

3 回答 3

7

我会先给你一个不好的方法来做到这一点。如果插入这些行:

insert into foo (row,column,txt) values (1,1,'First Insert');
insert into foo (row,column,txt) values (1,2,'Second Insert');
insert into foo (row,column,txt) values (2,1,'First Insert');
insert into foo (row,column,txt) values (2,2,'Second Insert');

做一个

'select row from foo;' 

将为您提供以下内容:

 row
-----
   1
   1
   2
   2

不明显,因为它显示了行和列的所有可能组合。要查询获取一个行值,您可以添加一个列值:

select row from foo where column = 1;

但是你会得到这个警告:

Bad Request: Cannot execute this query as it might involve data filtering and thus may  have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING

行。然后用这个:

select row from foo where column = 1 ALLOW FILTERING;

 row
-----
   1
   2

伟大的。我想要的。不过,我们不要忽视这个警告。如果您只有少量行,例如 10000 行,那么这将不会对性能造成巨大影响。现在如果我有 10 亿呢?根据节点数量和复制因子,您的性能将受到严重影响。首先,查询必须扫描表中所有可能的行(读取全表扫描),然后过滤结果集的唯一值。在某些情况下,此查询将超时。鉴于此,可能不是您想要的。

您提到您担心插入多个表时会影响性能。多表插入是一种非常有效的数据建模技术。Cassandra 可以进行大量写入。至于同步很痛苦,我不知道您的确切应用程序,但我可以提供一般提示。

如果您需要不同的扫描,则需要考虑分区列。这就是我们所说的索引或查询表。在任何 Cassandra 数据模型中要考虑的重要事情是应用程序查询。如果我使用 IP 地址作为行,我可能会创建这样的东西来按顺序扫描我拥有的所有 IP 地址。

CREATE TABLE ip_addresses (
 first_quad int,
 last_quads ascii,
 PRIMARY KEY (first_quad, last_quads)
);

现在,在我的 192.xxx 地址空间中插入一些行:

insert into ip_addresses (first_quad,last_quads) VALUES (192,'000000001');
insert into ip_addresses (first_quad,last_quads) VALUES (192,'000000002');
insert into ip_addresses (first_quad,last_quads) VALUES (192,'000001001');
insert into ip_addresses (first_quad,last_quads) VALUES (192,'000001255');

为了获得 192 空间中的不同行,我这样做:

SELECT * FROM ip_addresses WHERE first_quad = 192;

 first_quad | last_quads
------------+------------
        192 |  000000001
        192 |  000000002
        192 |  000001001
        192 |  000001255

要获取每个地址,您只需要遍历 0-255 之间的每个可能的行键。在我的示例中,我希望应用程序要求特定范围以保持性能。您的应用程序可能有不同的需求,但希望您能在这里看到模式。

于 2013-09-01T15:59:24.073 回答
4

根据文档,从 CQL 版本 3.11 开始,cassandra 了解 DISTINCT 修饰符。所以你现在可以写

SELECT DISTINCT row FROM foo
于 2013-11-26T15:09:18.337 回答
0

@edofic

分区行键用作唯一索引来区分存储引擎中的不同行,因此从本质上讲,行键总是不同的。您不需要将 DISTINCT 放在 SELECT 子句中

例子

 INSERT INTO foo(row,column,txt) VALUES (1,1,'1-1');
 INSERT INTO foo(row,column,txt) VALUES (2,1,'2-1');
 INSERT INTO foo(row,column,txt) VALUES (1,2,'1-2');

然后

SELECT row FROM foo

将返回 2 个值:1 和 2

以下是 Cassandra 中的持久化方式

+----------+------------------+------ +
| 行键 | 列 1/值 | 列 2/值 |
+----------+------------------+------ +
| 1 | 1/'1' | 2/'2' |
| 2 | 1/'1' | |
+----------+------------------+------ +

于 2013-09-01T15:44:35.263 回答