是否可以仅使用复合分区键的一部分来查询cassandra表?

时间:2016-07-20 08:40:43

标签: cassandra data-modeling cql

考虑这样的表来存储用户的联系人 -

CREATE TABLE contacts {
    user_name text,
    contact_name text,
    contact_id int, 
    contact_data blob,
    PRIMARYKEY ((user, contact_name), contact_id)
    //          ^-- Note the composite partition key
}

复合分区键导致每个联系人一行。

假设有1亿用户,每个用户都有几百个联系人。

我可以使用

查找特定用户的特定联系人数据
SELECT contact_data FROM contacts WHERE user_name='foo' AND contact_name='bar'

但是,也可以使用类似

之类的内容查找用户的所有联系人姓名
SELECT contact_name FROM contacts WHERE user_name='foo'

? WHERE子句是否只包含构成主键的所有列中的一些?

编辑 - 我试过这个,而cassandra并不允许这样做。所以现在我的问题是,你如何建模数据以支持两个查询 -

  1. 获取特定用户的数据&接触
  2. 获取用户的所有联系人姓名
  3. 我可以想到两个选项 -

    1. 创建另一个包含user_name和contact_name的表,仅使用user_name作为主键。但是,如果用户有太多的联系人,那可能是一个广泛的问题吗?
    2. 在user_name上创建索引。但是,如果每个用户只有几百个联系人的100M用户,user_name会被视为高基数值,因此在索引中使用不好吗?

3 个答案:

答案 0 :(得分:1)

在RDBMS中,查询计划程序可能能够为该类查询创建有效的查询计划。但卡桑德拉不能。卡桑德拉必须做一个表扫描。 Cassandra努力不让你做出那些类型的查询。所以它应该拒绝它。

答案 1 :(得分:1)

不,你不能。如果你看一下cassandra如何存储数据的机制,你就会明白为什么你不能通过复合分区键的一部分进行查询。

Cassandra根据分区键在节点之间分配数据。写请求的协调器使用分区键上的murmur3算法生成散列令牌,并将写请求发送给令牌的所有者。(每个节点具有它拥有的令牌范围)。在读取期间,协调器再次基于分区密钥计算散列令牌,并将读取请求发送到令牌的所有者节点。

由于您使用的是复合分区密钥,因此在写入请求期间,密钥(user,contact_name)的所有组件都将用于生成散列令牌。此令牌的所有者节点具有整行。在读取请求期间,您必须提供密钥的所有组件来计算令牌,并将读取请求发送给该令牌的正确所有者。因此,Cassandra强制您提供整个分区键。

答案 2 :(得分:0)

您可以使用两个具有相同结构但不具有相同分区键的不同表:

CREATE TABLE contacts { user_name text, contact_name text, contact_id int, contact_data blob, PRIMARY KEY ((user_name, contact_name), contact_id) } CREATE TABLE contacts_by_users { user_name text, contact_name text, contact_id int, contact_data blob, PRIMARY KEY ((user_name), contact_id) }

使用此结构,您可以进行数据复制,并且必须手动维护这两个表。

如果您正在使用cassandra> 3.0,您还可以使用物化视图:

CREATE TABLE contacts { user_name text, contact_name text, contact_id int, contact_data blob, PRIMARY KEY ((user_name, contact_name), contact_id) } CREATE MATERIALIZED VIEW contracts_by_users AS SELECT * FROM contracts WHERE user_name IS NOT NULL AND contract_name IS NOT NULL AND contract_id IS NOT NULL PRIMARY KEY ((user_name), contract_name, contract_id) WITH CLUSTERING ORDER BY contract_name ASC

在这种情况下,您只需维护表contracts,视图将自动更新